package com.zmn.plat.business.impl.product.tariff;

import com.alibaba.fastjson.JSON;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.utils.math.MathUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.plat.business.interfaces.channel.ChannelServProductBService;
import com.zmn.plat.business.interfaces.channel.ChannelServiceCategoryBService;
import com.zmn.plat.business.interfaces.pilot.ChannelPriceBService;
import com.zmn.plat.business.interfaces.product.ProductBService;
import com.zmn.plat.business.interfaces.product.tariff.TariffProductBService;
import com.zmn.plat.business.interfaces.product.tariff.item.ProductServiceItemPriceBService;
import com.zmn.plat.business.interfaces.servcategory.ShowCategoryAssociationBService;
import com.zmn.plat.common.constant.OnePriceConsts;
import com.zmn.plat.common.constant.ProductConsts;
import com.zmn.plat.common.dictionary.ChannelRatioTypeEnum;
import com.zmn.plat.common.dictionary.PlatErrorCodeDict;
import com.zmn.plat.common.dto.brand.BaseBrandDRO;
import com.zmn.plat.common.dto.brand.BaseBrandPageDRO;
import com.zmn.plat.common.dto.product.tariff.TariffBackProductDRO;
import com.zmn.plat.common.dto.product.tariff.TariffProductDIO;
import com.zmn.plat.common.dto.product.tariff.TariffProductDRO;
import com.zmn.plat.common.dto.product.tariff.TariffProductPageDRO;
import com.zmn.plat.common.dto.product.tariff.brand.TariffBrandFactorDIO;
import com.zmn.plat.common.dto.product.tariff.category.*;
import com.zmn.plat.common.dto.product.tariff.item.*;
import com.zmn.plat.common.dto.product.tariff.servcategory.TariffServCategoryDRO;
import com.zmn.plat.common.dto.servcategory.ServCategoryChildrenDRO;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.manager.dictionary.MasterDict;
import com.zmn.plat.manager.dictionary.ProductDict;
import com.zmn.plat.model.dto.product.ProductTariffRelationDTO;
import com.zmn.plat.model.dto.product.tariff.BaseParamDTO;
import com.zmn.plat.model.dto.product.tariff.ItemFilterDTO;
import com.zmn.plat.model.dto.product.tariff.TariffProductRedisDTO;
import com.zmn.plat.model.dto.service.ItemPriceCalDTO;
import com.zmn.plat.model.entity.brand.BaseBrand;
import com.zmn.plat.model.entity.brand.BaseBrandTariffProductQuery;
import com.zmn.plat.model.entity.brand.BaseBrandTariffQuery;
import com.zmn.plat.model.entity.category.BaseCategory;
import com.zmn.plat.model.entity.category.BaseCategoryAttributeEnum;
import com.zmn.plat.model.entity.category.BaseCategoryQuery;
import com.zmn.plat.model.entity.category.ServCategAndCategTwoQuery;
import com.zmn.plat.model.entity.channel.ChannelServiceCategory;
import com.zmn.plat.model.entity.pilot.SupportPilotVO;
import com.zmn.plat.model.entity.product.*;
import com.zmn.plat.model.entity.servcategory.ServAssCategoryQuery;
import com.zmn.plat.model.entity.servcategory.ServCategory;
import com.zmn.plat.model.entity.servcategory.ShowCategoryAssociationVO;
import com.zmn.plat.model.vo.brand.factor.BrandFactorRatioVo;
import com.zmn.plat.model.vo.product.ServProductVO;
import com.zmn.plat.model.vo.product.relation.ServProductRelationVO;
import com.zmn.plat.model.vo.product.relation.ServTariffProductRelationVO;
import com.zmn.plat.model.vo.product.tariff.TariffProductItemPriceTariffQueryVO;
import com.zmn.plat.model.vo.product.tariff.TariffProductItemPriceTariffVO;
import com.zmn.plat.model.vo.product.tariff.TariffProductRelationVO;
import com.zmn.plat.model.vo.product.tariff.item.price.ProductServiceItemExcutePriceQueryVo;
import com.zmn.plat.model.vo.product.tariff.item.price.ProductServiceItemExcutePriceResultVo;
import com.zmn.plat.model.vo.service.tariff.ChannelServiceTariffVO;
import com.zmn.plat.persistence.interfaces.channel.ChannelServiceCategoryDAO;
import com.zmn.plat.persistence.interfaces.servcategory.ServAssCategoryDao;
import com.zmn.plat.services.interfaces.area.BaseAreaService;
import com.zmn.plat.services.interfaces.brand.BaseBrandService;
import com.zmn.plat.services.interfaces.category.BaseCategoryAttributeEnumService;
import com.zmn.plat.services.interfaces.category.BaseCategoryService;
import com.zmn.plat.services.interfaces.channel.ChannelServiceCategoryService;
import com.zmn.plat.services.interfaces.channel.tariff.ChannelTariffService;
import com.zmn.plat.services.interfaces.pilot.ChannelPriceCityService;
import com.zmn.plat.services.interfaces.pilot.ChannelPriceService;
import com.zmn.plat.services.interfaces.product.ServProductRelationService;
import com.zmn.plat.services.interfaces.product.ServProductService;
import com.zmn.plat.services.interfaces.product.ServTariffProductRelationService;
import com.zmn.plat.services.interfaces.product.tariff.item.TariffProductServiceItemService;
import com.zmn.plat.services.interfaces.servcategory.ServCategoryService;
import com.zmn.plat.services.interfaces.servcategory.ShowCategoryAssociationService;
import com.zmn.plat.utils.bean.BeanCopyUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * @author tanbiao
 * @description:计价器相关接口
 * @modifier
 * @since 2020/3/25 14:35
 **/
@Service
@Slf4j
public class TariffProductBServiceImpl implements TariffProductBService {
    private final List<Byte> LEVEL_LIST = Arrays.asList(new Byte("1"), new Byte("2"));
    @Resource
    private ShowCategoryAssociationService showCategoryAssociationService;
    @Resource
    private ShowCategoryAssociationBService showCategoryAssociationBService;
    @Resource
    private ChannelTariffService channelTariffService;
    @Resource
    private TariffProductServiceItemService tariffProductFaultItemService;
    @Resource
    private ServProductService servProductService;
    @Resource
    private ServProductRelationService servProductRelationService;
    @Resource
    private BaseCategoryService baseCategoryService;
    @Resource
    private BaseBrandService baseBrandService;
    @Resource
    private ServTariffProductRelationService tariffProductRelationService;
    @Resource
    private ProductServiceItemPriceBService productFaultItemPriceBService;
    @Resource
    private TariffProductBService tariffProductBService;
    @Resource
    private BaseCategoryAttributeEnumService baseCategoryAttributeEnumService;
    @Resource
    private ChannelPriceService channelPriceService;
    @Resource
    private ChannelPriceCityService channelPriceCityService;
    @Resource
    private BaseAreaService baseAreaService;
    @Resource
    private ChannelServiceCategoryBService channelServiceCategoryBService;
    @Resource
    private ChannelServiceCategoryService channelServiceCategoryService;
    @Resource
    private ChannelPriceBService channelPriceBService;
    @Resource
    private ChannelServProductBService channelServProductBService;
    @Resource
    ServCategoryService servCategoryService;
    @Resource
    ProductBService productBService;
    @Resource
    ChannelServiceCategoryDAO channelServiceCategoryDAO;
    @Resource
    ServAssCategoryDao servAssCategoryDao;

    // 产品属性本地缓存
    private Cache<Integer, String> productEnuCache = CacheBuilder.newBuilder().expireAfterWrite(240, TimeUnit.HOURS).build();

    @Override
    public List<TariffServCategoryDRO> listServCategoryByChannelIdAndCityIdAndTariffCategoryId(TariffCategoryRelationDIO dio) {
        if (Objects.isNull(dio) || NumberUtil.isNullOrZero(dio.getChannelId()) || NumberUtil.isNullOrZero(dio.getCityId()) || NumberUtil.isNullOrZero(dio.getShowCategId())
                || NumberUtil.isNullOrZero(dio.getFilterTariff())) {
            log.error("listServCategoryByChannelIdAndCityIdAndTariffCategoryId error.dio={},errorCode:{}", dio, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }

        List<ShowCategoryAssociationVO> voList =
                tariffProductBService.listAviableShowCategoryAssociation(dio.getChannelId(), dio.getCityId(), dio.getShowCategId(), dio.getFilterTariff(), dio.getBizType());
        List<Integer> showServCategIds = new ArrayList<>();
        List<TariffServCategoryDRO> dros = new ArrayList<>();
        BeanCopier copier = BeanCopier.create(ShowCategoryAssociationVO.class, TariffServCategoryDRO.class, false);

        for (ShowCategoryAssociationVO vo : voList) {
            if (!showServCategIds.contains(vo.getShowServCategId())) {
                showServCategIds.add(vo.getShowServCategId());
                TariffServCategoryDRO tariffServCategoryDRO = new TariffServCategoryDRO();
                copier.copy(vo, tariffServCategoryDRO, null);
                dros.add(tariffServCategoryDRO);
            }
        }
        return dros;
    }

    @Override
    public TariffProductPageDRO listPageByTariffProductDIO(TariffProductDIO tariffProductDIO) {
        if (Objects.isNull(tariffProductDIO) || !NumberUtil.isPositiveInteger(tariffProductDIO.getCityId()) || !NumberUtil.isPositiveInteger(tariffProductDIO.getChannelId())
                || !NumberUtil.isPositiveInteger(tariffProductDIO.getServCategId()) || !NumberUtil.isPositiveInteger(tariffProductDIO.getCategId())
                || !NumberUtil.isPositiveInteger(tariffProductDIO.getFilterTariff())) {
            log.error("listPageByTariffProductDIO error.tariffProductDIO={}，errorCode:{}", tariffProductDIO, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }
        TariffProductPageDRO tariffProductPageDRO = new TariffProductPageDRO();
        ServProductQuery servProductQuery = new ServProductQuery();
        if (NumberUtil.isPositiveInteger(tariffProductDIO.getPageNum())) {
            servProductQuery.setPageIndex(tariffProductDIO.getPageNum());
        }
        if (NumberUtil.isPositiveInteger(tariffProductDIO.getPageSize())) {
            servProductQuery.setPageSize(tariffProductDIO.getPageSize());
        }
        // 查询改分类下配置了价格表的所有后台产品
        TariffProductRedisDTO redisDTO = new TariffProductRedisDTO();
        BeanCopyUtils.copyProperties(tariffProductDIO, redisDTO);
        redisDTO.setShowType(ProductDict.EC_PRODUCT_TYPE);
        List<TariffProductItemPriceTariffVO> productList = tariffProductBService.listRelatedTariffProductByRedisDTO(redisDTO);
        // 满足条件的后台产品
        List<Integer> productGroupList = productList.stream().map(e -> e.getProductId()).distinct().collect(Collectors.toList());
        servProductQuery.setProductIds(productGroupList);
        // 考虑业务类型三者的业务类型必须和传入的参数的业务类型保持一致
        if (Objects.equals(tariffProductDIO.getFilterTariff(), GlobalConsts.YES)) {
            servProductQuery.setBizType(redisDTO.getBizType());
        }

        // 根据后台产品查询对应的计价器产品,满足前台产品开启，同时后台产品状态和计价器状态开启
        log.info("listPageByTariffProductDIO.listPageByTariffProductIds 参数为：{}", JSON.toJSONString(servProductQuery));
        List<ServProductVO> servProductVOList = tariffProductFaultItemService.listPageByTariffProductIds(servProductQuery);
        List<TariffProductDRO> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(servProductVOList)) {
            BeanCopier copier = BeanCopier.create(ServProductVO.class, TariffProductDRO.class, false);
            list = servProductVOList.stream().map(e -> {
                TariffProductDRO dro = new TariffProductDRO();
                copier.copy(e, dro, null);
                return dro;
            }).collect(Collectors.toList());
            tariffProductPageDRO.setTotalCount(servProductQuery.getTotalCount());
            tariffProductPageDRO.setProductList(list);
        }
        return tariffProductPageDRO;
    }

    @Override
    public List<TariffProductItemDRO> listByTariffProductItemCategDIO(TariffProductItemCategDIO tariffProductFaultItemCategDIO) {
        if (Objects.isNull(tariffProductFaultItemCategDIO) || !NumberUtil.isPositiveInteger(tariffProductFaultItemCategDIO.getCityId())
                || !NumberUtil.isPositiveInteger(tariffProductFaultItemCategDIO.getChannelId()) || !NumberUtil.isPositiveInteger(tariffProductFaultItemCategDIO.getFaultCategId())
                || !NumberUtil.isPositiveInteger(tariffProductFaultItemCategDIO.getTariffProductId()) || !NumberUtil.isPositiveInteger(tariffProductFaultItemCategDIO.getFilterTariff())) {
            log.error("listByTariffProductItemCategDIO error.tariffProductFaultItemCategDIO：{}", tariffProductFaultItemCategDIO);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }

        List<TariffProductItemDRO> list = new ArrayList<>();
        ItemFilterDTO dto = new ItemFilterDTO();
        BeanCopyUtils.copyProperties(tariffProductFaultItemCategDIO, dto);
        List<TariffProductItemPriceTariffVO> filterList = filterBySelectItemIds(dto);
        Integer faultCategId = tariffProductFaultItemCategDIO.getFaultCategId();
        // 根据故障类型进行数据筛选
        filterList = filterList.stream().filter(e -> Objects.equals(e.getFaultCategId(), faultCategId)).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(filterList)) {
            List<Integer> itemIds = new ArrayList<>();
            BeanCopier copier = BeanCopier.create(TariffProductItemPriceTariffVO.class, TariffProductItemDRO.class, false);
            for (TariffProductItemPriceTariffVO e : filterList) {
                if (!itemIds.contains(e.getItemId())) {
                    itemIds.add(e.getItemId());
                    TariffProductItemDRO dro = new TariffProductItemDRO();
                    copier.copy(e, dro, null);
                    list.add(dro);
                }
            }
        }
        return list;
    }

    @Override
    public List<TariffCategoryDRO> listByTariffCategoryDIO(TariffCategoryDIO tariffCategoryDIO) {
        if (Objects.isNull(tariffCategoryDIO) || !NumberUtil.isPositiveInteger(tariffCategoryDIO.getCityId()) || !NumberUtil.isPositiveInteger(tariffCategoryDIO.getChannelId())
                || !NumberUtil.isPositiveInteger(tariffCategoryDIO.getTariffProductId()) || CollectionUtils.isEmpty(tariffCategoryDIO.getItemIds())
                || !NumberUtil.isPositiveInteger(tariffCategoryDIO.getFilterTariff())) {
            log.error("listByTariffCategoryDIO error.tariffCategoryDIO：{},errorCode:{}", tariffCategoryDIO, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }

        List<TariffCategoryDRO> list = new ArrayList<>();
        ItemFilterDTO dto = new ItemFilterDTO();
        BeanCopyUtils.copyProperties(tariffCategoryDIO, dto);
        // 筛选出满足所选项目id的所有产品，再进行归并，取产品二级分类列表
        List<TariffProductItemPriceTariffVO> filterList = filterBySelectItemIds(dto);
        Integer servCategId = filterList.get(0).getServCategId();
        List<Integer> categIds = filterList.stream().map(e -> e.getCategId()).distinct().collect(Collectors.toList());
        List<BaseCategory> categories = new ArrayList<>();
        if (!CollectionUtils.isEmpty(categIds)) {
            BaseCategoryQuery baseCategoryQuery = new BaseCategoryQuery();
            baseCategoryQuery.setCategIds(categIds);
            log.info("listByTariffCategoryDIO.listByQuery 参数为：{}", JSON.toJSONString(baseCategoryQuery));
            categories = baseCategoryService.listByQuery(baseCategoryQuery);
        }
        if (!CollectionUtils.isEmpty(categories)) {
            BeanCopier copier = BeanCopier.create(BaseCategory.class, TariffCategoryDRO.class, false);
            list = categories.stream().map(e -> {
                TariffCategoryDRO dro = new TariffCategoryDRO();
                copier.copy(e, dro, null);
                dro.setServCategId(servCategId);
                return dro;
            }).collect(Collectors.toList());
        }
        return list;
    }

    @Override
    public List<TariffBackProductDRO> listProductByProductFaultCategDIO(TariffProductCategoryDIO productFaultDIO) {
        if (Objects.isNull(productFaultDIO) || !NumberUtil.isPositiveInteger(productFaultDIO.getServCategId()) || !NumberUtil.isPositiveInteger(productFaultDIO.getCityId())
                || !NumberUtil.isPositiveInteger(productFaultDIO.getCategId()) || !NumberUtil.isPositiveInteger(productFaultDIO.getChannelId())
                || !NumberUtil.isPositiveInteger(productFaultDIO.getTariffProductId()) || CollectionUtils.isEmpty(productFaultDIO.getItemIds())
                || !NumberUtil.isPositiveInteger(productFaultDIO.getFilterTariff())) {
            log.error("listProductByProductFaultCategDIO error.productFaultDIO：{},errorCode:{}", productFaultDIO, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }
        // 筛选出满足所选项目id的所有产品，再进行归并，取产品二级分类列表
        ItemFilterDTO dto = new ItemFilterDTO();
        BeanCopyUtils.copyProperties(productFaultDIO, dto);
        List<TariffProductItemPriceTariffVO> filterList = filterBySelectItemIds(dto);
        Integer servcategId = productFaultDIO.getServCategId();
        Integer categId = productFaultDIO.getCategId();
        // 根据服务分类和二级分类过滤
        List<TariffProductItemPriceTariffVO> categIdFilterList =
                filterList.stream().filter(e -> Objects.equals(e.getServCategId(), servcategId) && Objects.equals(e.getCategId(), categId)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(categIdFilterList)) {
            log.info("listProductByProductFaultCategDIO根据传入的参数，根据服务分类和二级分类过滤，无满足条件的数据，返回空，code={}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_FILTER_BY_SERVCATEG_CATEG_NO_DATA);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_FILTER_BY_SERVCATEG_CATEG_NO_DATA);
        }
        // 去掉重复的后台产品数据
        categIdFilterList = categIdFilterList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getProductId()))), ArrayList::new));

        List<TariffBackProductDRO> dros = new ArrayList<>();
        if (!CollectionUtils.isEmpty(categIdFilterList)) {
            BeanCopier copier = BeanCopier.create(TariffProductItemPriceTariffVO.class, TariffBackProductDRO.class, false);
            dros = categIdFilterList.stream().map(servProduct -> {
                TariffBackProductDRO servProductDRO = new TariffBackProductDRO();
                copier.copy(servProduct, servProductDRO, null);
                return servProductDRO;
            }).collect(Collectors.toList());
        }
        return dros;
    }

    @Override
    public BaseBrandPageDRO listPageBrandByBrandFactorDIO(TariffBrandFactorDIO faultTariffBrandRatioDIO) {
        if (Objects.isNull(faultTariffBrandRatioDIO) || !NumberUtil.isPositiveInteger(faultTariffBrandRatioDIO.getServCategId())
                || !NumberUtil.isPositiveInteger(faultTariffBrandRatioDIO.getCategOneId()) || !NumberUtil.isPositiveInteger(faultTariffBrandRatioDIO.getCategTwoId())
                || !NumberUtil.isPositiveInteger(faultTariffBrandRatioDIO.getChannelId()) || !NumberUtil.isPositiveInteger(faultTariffBrandRatioDIO.getTariffProductId())
                || !NumberUtil.isPositiveInteger(faultTariffBrandRatioDIO.getCityId()) || !NumberUtil.isPositiveInteger(faultTariffBrandRatioDIO.getFilterTariff())) {
            log.error("listPageBrandByBrandFactorDIO error.faultTariffBrandRatioDIO：{}，errorCode:{}", faultTariffBrandRatioDIO,
                    PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }

        List<BaseBrandDRO> baseBrandDROS = new ArrayList<>();
        BaseBrandTariffProductQuery query = new BaseBrandTariffProductQuery();
        Integer servCategId = faultTariffBrandRatioDIO.getServCategId();
        Integer categId = faultTariffBrandRatioDIO.getCategTwoId();

        if (faultTariffBrandRatioDIO.getPageNum() != null && faultTariffBrandRatioDIO.getPageNum() > 0) {
            query.setPageIndex(faultTariffBrandRatioDIO.getPageNum());
        }
        if (faultTariffBrandRatioDIO.getPageSize() != null && faultTariffBrandRatioDIO.getPageSize() > 0) {
            query.setPageSize(faultTariffBrandRatioDIO.getPageSize());
        }
        TariffProductRedisDTO redisDTO = new TariffProductRedisDTO();
        BeanCopyUtils.copyProperties(faultTariffBrandRatioDIO, redisDTO);
        redisDTO.setServCategId(servCategId);
        redisDTO.setCategId(categId);
        redisDTO.setShowType(ProductDict.EC_PRODUCT_TYPE);
        // 配置了品牌的所有数据，此处取的是品牌，那么过滤不同的品牌返回即可
        List<BrandFactorRatioVo> brandList = tariffProductBService.listConfigedBrandByRedisDTO(redisDTO);
        List<Integer> brandIds = new ArrayList<>();
        List<BrandFactorRatioVo> distinctbrandList = new ArrayList<>();
        for (BrandFactorRatioVo brandFactorRatioVo : brandList) {
            if (!brandIds.contains(brandFactorRatioVo.getBrandId())) {
                brandIds.add(brandFactorRatioVo.getBrandId());
                distinctbrandList.add(brandFactorRatioVo);
            }
        }

        // 分页
        List<BrandFactorRatioVo> pages = listPage(distinctbrandList, query.getPageIndex(), query.getPageSize());
        baseBrandDROS = pages.stream().map(e -> {
            BaseBrandDRO dro = new BaseBrandDRO();
            dro.setBrandId(e.getBrandId());
            dro.setName(e.getBrandName());
            dro.setIcon(e.getBrandIcon());
            dro.setFirstLetter(e.getFirstLetter());
            return dro;
        }).collect(Collectors.toList());

        BaseBrandPageDRO dro = new BaseBrandPageDRO();
        dro.setBrandList(baseBrandDROS);
        dro.setTotalCount(distinctbrandList.size());
        return dro;
    }

    /**
     * 功能描述 根据后台服务分类一级分类查询配置了品牌的数据，优先渠道，其次基础， 存在二级分类一定存在一级分类，因此只需要判断一级分类是否存在数据即可
     *
     * @param
     * @return java.util.List<com.zmn.plat.model.vo.brand.factor.BrandFactorVo>
     * @author tanbiao
     * @modifier
     * @since 2020/4/16
     */
    @Cacheable(
            key = "'dubbo:tariff:brand:channel:' + #redisDTO.channelId + ':city:' + #redisDTO.cityId + ':bizType:' "
                    + "+ #redisDTO.bizType + ':servCategId:' + #redisDTO.servCategId + ':categId:' + #redisDTO.categId + ':showType:'"
                    + " + #redisDTO.showType+ ':tariffProductId:' + #redisDTO.tariffProductId+ ':filterTariff:' + #redisDTO.filterTariff",
            cacheNames = "redis5m", unless = "#result == null || #result.size() <= 0")
    @Override
    public List<BrandFactorRatioVo> listConfigedBrandByRedisDTO(TariffProductRedisDTO redisDTO) {
        log.info("listConfigedBrandByRedisDTO param is :{}", JSON.toJSONString(redisDTO));
        BaseBrandTariffProductQuery query = new BaseBrandTariffProductQuery();
        List<TariffProductItemPriceTariffVO> tariffProductItemPriceTariffVOS = listProductByChannelIdAndCityIdAndBizTypeAndTariffProductId(redisDTO);
        List<String> productList = new ArrayList<>();
        List<BaseBrandTariffQuery> queryList = new ArrayList<>();
        for (TariffProductItemPriceTariffVO e : tariffProductItemPriceTariffVOS) {
            String key = e.getServCategId() + "_" + e.getCategOneId() + "_" + e.getCategId() + "_" + e.getProductId();
            if (!productList.contains(key)) {
                productList.add(key);
                BaseBrandTariffQuery brandQuery = new BaseBrandTariffQuery();
                brandQuery.setCategTwoId(e.getCategId());
                brandQuery.setServCategId(e.getServCategId());
                brandQuery.setCategOneId(e.getCategOneId());
                queryList.add(brandQuery);
            }
        }
        query.setBrandTariffQueries(queryList);
        Integer avaliableChannelId = channelServiceCategoryBService.getAvailableCategoryChannelId(redisDTO.getChannelId());
        query.setChannelId(avaliableChannelId);

        List<BrandFactorRatioVo> brandList = new ArrayList<>();
        // 获取品牌，先查询渠道是否配置了品牌，渠道配置了品牌，以渠道为主否则以基础的为主
        query.setRatioType(ChannelRatioTypeEnum.BRAND);
        query.setBizType(redisDTO.getBizType());
        log.info("listConfigedBrandByRedisDTO.listTariffChannelBrandPageByQuery 参数为：{}", JSON.toJSONString(query));
        brandList = baseBrandService.listTariffChannelBrandPageByQuery(query);
        if (CollectionUtils.isEmpty(brandList)) {
            log.debug("渠道未配置品牌，取基础数据的品牌数据");
            brandList = baseBrandService.listTariffBrandPageByQuery(query);
        }
        if (CollectionUtils.isEmpty(brandList)) {
            log.error("计价器产品对应的后台产品未配置品牌，返回空,code={}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_BRAND_NO_DATA);
            // 品牌不存在允许跳过
            return Lists.newArrayList();
        }
        // 对品牌进行过滤，返回不重复的数据，优先二级分类，二级不存在，返回一级
        List<BrandFactorRatioVo> filteredResDto = filterByTariffProductId(query.getBrandTariffQueries(), brandList);
        return filteredResDto;
    }

    @Override
    public TariffCategoryPageDRO listCategoryPageByCategoryDIO(TariffCategoryPageDIO tariffCategoryPageDIO) {
        boolean isShowTypeAvaliable =
                Objects.equals(tariffCategoryPageDIO.getShowType(), ProductConsts.ERP_PRODUCT_TYPE) || Objects.equals(tariffCategoryPageDIO.getShowType(), ProductConsts.EC_PRODUCT_TYPE);
        if (Objects.isNull(tariffCategoryPageDIO) || StringUtil.isBlank(tariffCategoryPageDIO.getTariffName()) || !NumberUtil.isPositiveInteger(tariffCategoryPageDIO.getFilterTariff())
                || !isShowTypeAvaliable || !NumberUtil.isPositiveInteger(tariffCategoryPageDIO.getChannelId()) || !NumberUtil.isPositiveInteger(tariffCategoryPageDIO.getCityId())
                || Objects.isNull(tariffCategoryPageDIO.getLevel()) || !LEVEL_LIST.contains(tariffCategoryPageDIO.getLevel())) {
            log.error("listCategoryPageByCategoryDIO error.tariffCategoryPageDIO：{},errorCode:{}", tariffCategoryPageDIO, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }

        TariffCategoryPageDRO dro = new TariffCategoryPageDRO();
        BaseCategoryQuery query = new BaseCategoryQuery();
        query.setTariffName(tariffCategoryPageDIO.getTariffName());
        query.setShowType(tariffCategoryPageDIO.getShowType());
        query.setLevel(tariffCategoryPageDIO.getLevel());
        if (tariffCategoryPageDIO.getPageNum() != null && tariffCategoryPageDIO.getPageNum() > 0) {
            query.setPageIndex(tariffCategoryPageDIO.getPageNum());
        }
        if (tariffCategoryPageDIO.getPageSize() != null && tariffCategoryPageDIO.getPageSize() > 0) {
            query.setPageSize(tariffCategoryPageDIO.getPageSize());
        }
        List<BaseCategory> baseCategoryList = new ArrayList<>();
        // 查询全部，再内存分页
        query.setPageSize(10000);
        // 前台产品二级分类模糊匹配，状态和计价器状态开启
        log.info("listCategoryPageByCategoryDIO.listPageByFaultQuery 参数为：{}", JSON.toJSONString(query));
        List<BaseCategory> list = baseCategoryService.listPageByFaultQuery(query);

        if (CollectionUtils.isEmpty(list)) {
            log.error("listCategoryPageByCategoryDIO无相应的二级分类数据,cdoe={}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_SHOW_CATEGNAME_NO_AVIABLE_TARIFF_DATA);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_SHOW_CATEGNAME_NO_AVIABLE_TARIFF_DATA);
        }
        List<ShowCategoryAssociationVO> aviableCategs = new ArrayList<>();
        for (BaseCategory category : list) {
            try {
                // 缓存二级分类对应的可用的服务分类
                List<ShowCategoryAssociationVO> enableList = tariffProductBService.listAviableShowCategoryAssociation(tariffCategoryPageDIO.getChannelId(), tariffCategoryPageDIO.getCityId(),
                        category.getCategId(), tariffCategoryPageDIO.getFilterTariff(), tariffCategoryPageDIO.getBizType());
                if (!CollectionUtils.isEmpty(enableList)) {
                    aviableCategs.addAll(enableList);
                    baseCategoryList.add(category);
                }
            } catch (PlatException e) {
                log.error("关键字筛选的服务分类错误，code={}", e.getErrorCode());
            }
        }

        if (CollectionUtils.isEmpty(baseCategoryList)) {
            log.error("listCategoryPageByCategoryDIO 关键字模糊匹配无合法的二级分类数据,code={}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_SHOW_CATEGNAME_NO_AVIABLE_TARIFF_DATA);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_SHOW_CATEGNAME_NO_AVIABLE_TARIFF_DATA);
        }
        // 内存分页
        baseCategoryList = listPage(baseCategoryList, query.getPageIndex(), query.getPageSize());
        log.debug("返回结果为：{}" + JSON.toJSONString(baseCategoryList));
        List<TariffCategoryDRO> items = new ArrayList<>();
        BeanCopier copier = BeanCopier.create(BaseCategory.class, TariffCategoryDRO.class, false);
        for (BaseCategory categ : baseCategoryList) {
            TariffCategoryDRO tariffCategoryDRO = new TariffCategoryDRO();
            copier.copy(categ, tariffCategoryDRO, null);
            items.add(tariffCategoryDRO);
        }
        dro.setCategoryList(items);
        dro.setTotalCount(baseCategoryList.size());
        return dro;
    }

    @Cacheable(key = "'dubbo:tariff:showcateg:channel:' + #p0 + ':city:' + #p1 + ':showCategId:' + #p2 + ':filterTariff:' + #p3+ ':bizType:' + #p4", cacheNames = "redis5m",
            unless = "#result == null || #result.size() <= 0")
    @Override
    public List<ShowCategoryAssociationVO> listAviableShowCategoryAssociation(Integer channelId, Integer cityId, Integer showCategId, Integer filterTariff, Integer bizType) {
        log.info("listAviableShowCategoryAssociation param is :{},{},{},{},{}", channelId, cityId, showCategId, filterTariff, bizType);
        List<ShowCategoryAssociationVO> resultList = new ArrayList<>();
        Integer avaliableChannelId = null;
        List<Integer> showCategIds = Arrays.asList(showCategId);
        List<ShowCategoryAssociationVO> showCategoryAssociationListVOS = showCategoryAssociationBService.listByShowCategoryIdsFroTariff(showCategIds);
        if (CollectionUtils.isEmpty(showCategoryAssociationListVOS)) {
            log.info("listAviableShowCategoryAssociation 无对应的合法的关联关系，channelId={},cityId={},showCategId={},code={}", channelId, cityId, showCategId,
                    PlatErrorCodeDict.ERROR_CODE_PRODUCT_SHOW_CATEG_NO_RELATION);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_SHOW_CATEG_NO_RELATION);
        }
        List<Integer> servCategIds = new ArrayList<>();
        List<Integer> categIds = new ArrayList<>();
        showCategoryAssociationListVOS.forEach(e -> {
            servCategIds.add(e.getShowServCategId());
            categIds.add(e.getShowCategId());
        });
        // 批量查询支持计价器试点的数据,需要考虑试点配置的情况下确定支持计价器试点的数据
        if (Objects.equals(filterTariff, GlobalConsts.YES)) {
            // 查询支持计价器的分类列表
            SupportPilotVO supportPilotVO = channelPriceBService.listPilotCategs(channelId, cityId, OnePriceConsts.TARIFF, null, null);
            if (Objects.isNull(supportPilotVO) || CollectionUtils.isEmpty(supportPilotVO.getServCategIdList())) {
                log.info("listSupportTariffCategory 二级分类下的数据不支持计价器试点，channelId={},cityId={},showCategId={},code={}", channelId, cityId, showCategId,
                        PlatErrorCodeDict.ERROR_CODE_PRODUCT_SHOW_CATEG_NOT_SUPPORT_TARIFF);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_SHOW_CATEG_NOT_SUPPORT_TARIFF);
            }
            // 筛选出支持计价器试点的数据,只考虑服务分类，二级分类是相同的
            List<Integer> supportServCategIds = supportPilotVO.getServCategIdList().stream().map(e -> e.getServCategId()).distinct().collect(Collectors.toList());

            //检查当前渠道开通的试点是否存在开通的分类
            List<ChannelServiceCategory> list = channelServiceCategoryService.listByChannelIdAndCategIdAndShowType(channelId, showCategIds, ProductDict.EC_PRODUCT_TYPE);
            if (CollectionUtils.isEmpty(list)) {
                avaliableChannelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
                log.info("二级渠道没有用可用的分类，取一级渠道的id,channelId:{},avaliableChannelId:{}", channelId, avaliableChannelId);
                list = channelServiceCategoryService.listByChannelIdAndCategIdAndShowType(avaliableChannelId, showCategIds, ProductDict.EC_PRODUCT_TYPE);
            }
            if (CollectionUtils.isEmpty(list)) {
                log.info("checkSupport二级渠道继承的一级渠道无可用的分类,errorCode:{}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PARENT_CHANNEL_TIME_OUT_NO_CATEGORY);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PARENT_CHANNEL_TIME_OUT_NO_CATEGORY);
            }

            Set<Integer> channelSupportServCategIds = list.stream().map(e -> e.getServCategId()).collect(Collectors.toSet());
            //二者交集
            channelSupportServCategIds.retainAll(supportServCategIds);
            supportServCategIds.clear();
            supportServCategIds.addAll(channelSupportServCategIds);
            if (CollectionUtils.isEmpty(supportServCategIds)) {
                log.info("checkSupport 二级渠道继承的一级渠道和二级渠道的试点无交集,errorCode:{}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PARENT_CHANNEL_CATEGORY_NO_INTERSECTION);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PARENT_CHANNEL_CATEGORY_NO_INTERSECTION);
            }
            showCategoryAssociationListVOS = showCategoryAssociationListVOS.stream().filter(e -> supportServCategIds.contains(e.getShowServCategId())).collect(Collectors.toList());
        }

        // 根据二级分类是确定的，检查服务分类不同的数据集合
        List<Integer> selectedCategIds = new ArrayList<>();
        for (ShowCategoryAssociationVO showCategoryAssociationVO : showCategoryAssociationListVOS) {
            Integer showServCategId = showCategoryAssociationVO.getShowServCategId();
            if (!selectedCategIds.contains(showServCategId)) {
                selectedCategIds.add(showServCategId);
                TariffProductRedisDTO redisDTO = new TariffProductRedisDTO();
                redisDTO.setChannelId(channelId);
                redisDTO.setCityId(cityId);
                redisDTO.setBizType(bizType);
                redisDTO.setServCategId(showServCategId);
                redisDTO.setCategId(showCategId);
                redisDTO.setShowType(ProductDict.EC_PRODUCT_TYPE);
                redisDTO.setFilterTariff(filterTariff);
                redisDTO.setFilteredByKeyWord(GlobalConsts.YES);
                redisDTO.setAvaliableChannelId(avaliableChannelId);
                try {
                    List<TariffProductItemPriceTariffVO> productPriceTableList = tariffProductBService.listRelatedTariffProductByRedisDTO(redisDTO);
                    if (!CollectionUtils.isEmpty(productPriceTableList)) {
                        resultList.add(showCategoryAssociationVO);
                    }
                } catch (PlatException e) {
                    log.error("listRelatedTariffProductByRedisDTO error.query={}", redisDTO);
                }
            }
        }
        return resultList;
    }

    @Override
    public List<TariffProductItemPriceDRO> listItemPriceByProductIdAndItemIds(TariffProductItemPriceDIO tariffProductFaultItemPriceDIO) {
        if (Objects.isNull(tariffProductFaultItemPriceDIO) || !NumberUtil.isPositiveInteger(tariffProductFaultItemPriceDIO.getProductId())
                || !NumberUtil.isPositiveInteger(tariffProductFaultItemPriceDIO.getTariffProductId()) || !NumberUtil.isPositiveInteger(tariffProductFaultItemPriceDIO.getChannelId())
                || !NumberUtil.isPositiveInteger(tariffProductFaultItemPriceDIO.getCityId()) || CollectionUtils.isEmpty(tariffProductFaultItemPriceDIO.getItemIds())
                || !NumberUtil.isPositiveInteger(tariffProductFaultItemPriceDIO.getFilterTariff())) {
            log.error("listItemPriceByProductIdAndItemIds error.tariffProductFaultItemPriceDIO：{},errorCode:{}", tariffProductFaultItemPriceDIO,
                    PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }
        Integer productId = tariffProductFaultItemPriceDIO.getProductId();
        Integer channelId = tariffProductFaultItemPriceDIO.getChannelId();
        Integer cityId = tariffProductFaultItemPriceDIO.getCityId();
        Integer bizType = tariffProductFaultItemPriceDIO.getBizType();
        Integer brandId = tariffProductFaultItemPriceDIO.getBrandId();

        List<Integer> selectItems = tariffProductFaultItemPriceDIO.getItemIds();
        ItemFilterDTO dto = new ItemFilterDTO();
        BeanCopyUtils.copyProperties(tariffProductFaultItemPriceDIO, dto);
        List<TariffProductItemPriceTariffVO> filterList = filterBySelectItemIds(dto);
        // 当前产品所属的用户提交的项目集合
        filterList = filterList.stream().filter(e -> Objects.equals(e.getProductId(), productId) && selectItems.contains(e.getItemId())).collect(Collectors.toList());
        /********************************* 计算价格 ************************************************/
        for (TariffProductItemPriceTariffVO vo : filterList) {
            // 计算价格,区分城市定价还是系数定价，城市定价只考虑品牌系数
            productFaultItemPriceBService.calPriceDetail(vo, new ItemPriceCalDTO(channelId, cityId, brandId, bizType, tariffProductFaultItemPriceDIO.getDifficultRatioId()));
        }
        List<TariffProductItemPriceDRO> list = transVoListToDroList(filterList);
        return list;
    }

    // 后台二级分类不清楚
    @Override
    public List<TariffProductItemPriceUnknownDRO> listProductPriceByTariffProductId(TariffProductItemUnknowCategoryDIO categoryDIO) {
        if (Objects.isNull(categoryDIO) || !NumberUtil.isPositiveInteger(categoryDIO.getTariffProductId()) || !NumberUtil.isPositiveInteger(categoryDIO.getChannelId())
                || !NumberUtil.isPositiveInteger(categoryDIO.getCityId()) || CollectionUtils.isEmpty(categoryDIO.getItemIds()) || !NumberUtil.isPositiveInteger(categoryDIO.getFilterTariff())) {
            log.error("listProductPriceByTariffProductId error.categoryDIO：{}，errorCode:{}", categoryDIO, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }
        ItemFilterDTO dto = new ItemFilterDTO();
        BeanCopyUtils.copyProperties(categoryDIO, dto);
        List<TariffProductItemPriceTariffVO> list = filterBySelectItemIds(dto);
        // 不清楚只返回选择的数据
        list = list.stream().filter(e -> categoryDIO.getItemIds().contains(e.getItemId())).collect(Collectors.toList());
        List<TariffProductItemPriceUnknownDRO> dros = calcPriceAndTransVoToDro(list, categoryDIO.getChannelId(), categoryDIO.getCityId(), categoryDIO.getBizType(), categoryDIO.getBrandId());
        return dros;
    }

    // 后台产品不清楚
    @Override
    public List<TariffProductItemPriceUnknownDRO> listProductPriceByCategId(TariffProductItemUnknowProductDIO categoryDIO) {
        if (Objects.isNull(categoryDIO) || !NumberUtil.isPositiveInteger(categoryDIO.getCategId()) || !NumberUtil.isPositiveInteger(categoryDIO.getTariffProductId())
                || !NumberUtil.isPositiveInteger(categoryDIO.getChannelId()) || !NumberUtil.isPositiveInteger(categoryDIO.getCityId()) || CollectionUtils.isEmpty(categoryDIO.getItemIds())
                || !NumberUtil.isPositiveInteger(categoryDIO.getFilterTariff())) {
            log.error("listProductPriceByCategId error.categoryDIO：{}，errorCode:{}", categoryDIO, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }
        ItemFilterDTO dto = new ItemFilterDTO();
        BeanCopyUtils.copyProperties(categoryDIO, dto);
        Integer categId = categoryDIO.getCategId();
        List<TariffProductItemPriceTariffVO> list = filterBySelectItemIds(dto);
        list = list.stream().filter(e -> Objects.equals(e.getCategId(), categId)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(list)) {
            log.error("listProductPriceByCategId根据传入的参数无数据，返回空，code={}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_BACK_PRODUCT_PRICETABNE_NO_DATA);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_BACK_PRODUCT_PRICETABNE_NO_DATA);
        }
        list = list.stream().filter(e -> categoryDIO.getItemIds().contains(e.getItemId())).collect(Collectors.toList());
        List<TariffProductItemPriceUnknownDRO> dros = calcPriceAndTransVoToDro(list, categoryDIO.getChannelId(), categoryDIO.getCityId(), categoryDIO.getBizType(), categoryDIO.getBrandId());
        return dros;
    }

    @Override
    public List<TariffProductItemPriceDRO> listByProductItemPriceSplitItemDIO(TariffProductItemPriceSplitItemDIO faultItemPriceDIO) {
        if (Objects.isNull(faultItemPriceDIO) || !NumberUtil.isPositiveInteger(faultItemPriceDIO.getChannelId()) || !NumberUtil.isPositiveInteger(faultItemPriceDIO.getCityId())
                || !NumberUtil.isPositiveInteger(faultItemPriceDIO.getProductId()) || !NumberUtil.isPositiveInteger(faultItemPriceDIO.getFilterTariff())) {
            log.error("listByProductItemPriceSplitItemDIO error.faultItemPriceDIO：{}，errorCode:{}", faultItemPriceDIO, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }

        Integer productId = faultItemPriceDIO.getProductId();
        ServProduct servProduct = servProductService.findByKey(productId);
        if (Objects.isNull(servProduct)) {
            log.error("listByProductFaultItemPriceSplitItemDIO 产品对应的数据不存在，productId={},code={}", productId, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_RESULT_NOT_EXIST);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_RESULT_NOT_EXIST);
        }
        TariffProductRedisDTO redisDTO = new TariffProductRedisDTO();
        BeanCopyUtils.copyProperties(faultItemPriceDIO, redisDTO);
        redisDTO.setServCategId(servProduct.getServCategId());
        redisDTO.setCategId(servProduct.getCategId());
        redisDTO.setShowType(ProductDict.ERP_PRODUCT_TYPE);
        List<TariffProductItemPriceTariffVO> itemPriceVOs = tariffProductBService.listRelatedTariffProductByRedisDTO(redisDTO);
        itemPriceVOs = itemPriceVOs.stream().filter(e -> Objects.equals(e.getPriceStandard(), GlobalConsts.YES)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(itemPriceVOs)) {
            log.info("listByProductFaultItemPriceSplitItemDIO筛选之后无满足条件的数据，返回空,code={}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_PRICE_STANDARD_NO_DATA);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_PRICE_STANDARD_NO_DATA);
        }

        //存在品牌计算价格
        if (Objects.nonNull(faultItemPriceDIO.getBrandId())) {
            for (TariffProductItemPriceTariffVO vo : itemPriceVOs) {
                // 计算价格,区分城市定价还是系数定价，城市定价只考虑品牌系数
                productFaultItemPriceBService.calPriceDetail(vo, new ItemPriceCalDTO(faultItemPriceDIO.getChannelId(), faultItemPriceDIO.getCityId(), faultItemPriceDIO.getBrandId(), faultItemPriceDIO.getBizType(), faultItemPriceDIO.getDifficultId()));
            }
        }

        // 组装返回实体
        BeanCopier temCopier = BeanCopier.create(TariffProductItemPriceTariffVO.class, TariffProductItemPriceDRO.class, false);
        List<TariffProductItemPriceDRO> list = itemPriceVOs.stream().map(e -> {
            TariffProductItemPriceDRO dro = new TariffProductItemPriceDRO();
            temCopier.copy(e, dro, null);
            return dro;
        }).collect(Collectors.toList());


        return list;
    }

    @Override
    public List<TariffProductItemPriceDRO> listByProductItemDefaultDIO(TariffProductItemDefaultDIO faultItemPriceDIO) {
        if (Objects.isNull(faultItemPriceDIO) || !NumberUtil.isPositiveInteger(faultItemPriceDIO.getChannelId()) || !NumberUtil.isPositiveInteger(faultItemPriceDIO.getCityId())
                || !NumberUtil.isPositiveInteger(faultItemPriceDIO.getProductId()) || !NumberUtil.isPositiveInteger(faultItemPriceDIO.getFilterTariff())) {
            log.error("listByProductItemDefaultDIO error.faultItemPriceDIO：{}，errorCode:{}", faultItemPriceDIO, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }
        Integer productId = faultItemPriceDIO.getProductId();
        ServProduct servProduct = servProductService.findByKey(productId);
        if (Objects.isNull(servProduct)) {
            log.error("listByProductFaultItemDefaultDIO 产品对应的产品数据不存在，productId={},code={}", productId, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_RESULT_NOT_EXIST);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_RESULT_NOT_EXIST);
        }
        TariffProductRedisDTO redisDTO = new TariffProductRedisDTO();
        BeanCopyUtils.copyProperties(faultItemPriceDIO, redisDTO);
        redisDTO.setServCategId(servProduct.getServCategId());
        redisDTO.setCategId(servProduct.getCategId());
        redisDTO.setShowType(ProductDict.ERP_PRODUCT_TYPE);
        List<TariffProductItemPriceTariffVO> itemPriceVOs = tariffProductBService.listRelatedTariffProductByRedisDTO(redisDTO);
        itemPriceVOs = itemPriceVOs.stream().filter(e -> Objects.equals(e.getPriceStandard(), GlobalConsts.NO) && Objects.equals(e.getItemGeneral(), GlobalConsts.YES)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(itemPriceVOs)) {
            log.info("listByProductFaultItemDefaultDIO筛选之后无满足条件的数据，返回空,code={}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_PRICE_STANDARD_NO_DERAULT_ITEM_NO_DATA);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_PRICE_STANDARD_NO_DERAULT_ITEM_NO_DATA);
        }
        BeanCopier temCopier = BeanCopier.create(TariffProductItemPriceTariffVO.class, TariffProductItemPriceDRO.class, false);
        List<TariffProductItemPriceDRO> list = itemPriceVOs.stream().map(e -> {
            TariffProductItemPriceDRO dro = new TariffProductItemPriceDRO();
            temCopier.copy(e, dro, null);
            return dro;
        }).collect(Collectors.toList());
        return list;
    }

    @Override
    public List<ProductServiceItemExcutePriceResultVo> listByExcuteQuery(ProductServiceItemExcutePriceQueryVo query) {
        // 查询渠道配置的价格表，渠道没有配置价格表，取默认价格表，如果基础数据都没有配置价格表，那么返回空
        // 1.渠道是否配置了启用状态的价格表（渠道启用，价格表启用），若存在，那么用渠道返回的价格表id，不存在，执行2
        // 2.检查基础数据中是否配置了渠道相应的价格表，若不存在，返回空，存在，取默认的价格表（关联到产品上的，有点麻烦）
        if (Objects.isNull(query.getTariffType())) {
            // 还原原始的渠道id
            query.setChannelId(Objects.nonNull(query.getCurrentChannelId()) ? query.getCurrentChannelId() : query.getChannelId());
            log.error("listByExcuteQuery 价格表计价类型为空，返回空");
            return Collections.emptyList();
        }
        setQueryParams(query);

        log.info("listProductTariffRelationByQuery query={}", JSON.toJSONString(query));

        /***
         * 查询产品和价格表的关联关系，再对服务项进行关联,需要对产品和渠道进行过滤， productId为后台产品id，productName为前/后台产品名称， 如果为前台，那么产品id和产品名称不对应，主要是为了下方对产品名称进行翻译
         **/
        List<ChannelServiceTariffVO> productTariffList = channelTariffService.listProductTariffRelationByQuery(query);
        if (CollectionUtils.isEmpty(productTariffList)) {
            log.error("listByExcuteQuery 产品和价格表对应的关系数据不存在，返回空", query.getTariffId());
            // 还原原始的渠道id
            query.setChannelId(Objects.nonNull(query.getCurrentChannelId()) ? query.getCurrentChannelId() : query.getChannelId());
            return Collections.emptyList();
        }

        query.setProductTariffIdRelation(productTariffList);

        log.info("listByExcuteQuery query={}", JSON.toJSONString(query));

        // 根据产品id和价格表id对结果集进行翻译
        Map<String, ChannelServiceTariffVO> map = new HashMap<>();
        productTariffList.forEach(e -> map.put(e.getProductId() + "_" + e.getTariffId(), e));

        List<ProductServiceItemExcutePriceResultVo> queryVoList = tariffProductFaultItemService.listByExcuteQuery(query);
        if (CollectionUtils.isEmpty(queryVoList)) {
            log.error("listByExcuteQuery 价格表数据不存在，返回空", query.getTariffId());
            // 还原原始的渠道id
            query.setChannelId(Objects.nonNull(query.getCurrentChannelId()) ? query.getCurrentChannelId() : query.getChannelId());
            return Collections.emptyList();
        }
        // 过滤业务类型：如果是前台产品那么查出的数据对应的后台产品业务类型必须部分相同，价格表业务类型必须被后台产品的业务类型包含
        List<ProductServiceItemExcutePriceResultVo> cityResultVoList = new ArrayList<>(queryVoList.size());
        if (Objects.isNull(query.getFilterBizType()) || query.getFilterBizType()) {
            cityResultVoList.addAll(filterByBizType(query.getProductId(), query.getBizType(), queryVoList));
            if (CollectionUtils.isEmpty(cityResultVoList)) {
                log.error("listByExcuteQuery 考虑业务类型过滤，返回空", query.getTariffId());
                // 还原原始的渠道id
                query.setChannelId(Objects.nonNull(query.getCurrentChannelId()) ? query.getCurrentChannelId() : query.getChannelId());
                return Collections.emptyList();
            }
        }

        // 如果是城市定价，需要判断当前数据是否在开通的城市中，如果不在开通的城市中，取外层数据
        for (ProductServiceItemExcutePriceResultVo excutePriceResultVo : cityResultVoList) {
            ChannelServiceTariffVO channelFaultTariffVO = map.get(excutePriceResultVo.getProductId() + "_" + excutePriceResultVo.getTariffId());
            excutePriceResultVo.setPriceType(channelFaultTariffVO.getPriceType());

            if (Objects.isNull(excutePriceResultVo.getServiceMinutes())) {
                excutePriceResultVo.setServiceMinutes(GlobalConsts.NONE);
            }

            if (Objects.equals(excutePriceResultVo.getPriceStandard(), GlobalConsts.NO)) {
                // 非一口价,不区分系数类型（面议的处理）
                handPriceStandardNo(query, excutePriceResultVo, channelFaultTariffVO);
            } else {
                // 一口价
                handlePriceStandardYes(query, excutePriceResultVo, channelFaultTariffVO);
            }
        }
        // 还原原始的渠道id
        query.setChannelId(Objects.nonNull(query.getCurrentChannelId()) ? query.getCurrentChannelId() : query.getChannelId());
        return cityResultVoList;
    }


    @Cacheable(
            key = "'dubbo:item:channel:' + #query.channelId + ':city:' + #query.cityId + ':bizType:' + #query.bizType "
                    + " + ':productId:' + #query.productId + ':brandId:' + #query.brandId+ ':tariffType:' " +
                    "+ #query.tariffType + ':filterBizType:' + #query.filterBizType+ ':difficultId:' + #query.difficultId",
            cacheNames = "redis5m", unless = "#result == null || #result.size() <= 0")
    @Override
    public List<ProductServiceItemExcutePriceResultVo> listByExcuteQueryCached(ProductServiceItemExcutePriceQueryVo query) {
        log.info("listByExcuteQueryCached param is :{}", JSON.toJSONString(query));
        return listByExcuteQuery(query);
    }

    /**
     * 功能描述 :渠道城市下指定的服务分类和后台二级分类的配置有价格表的所有后台数据 支持查询前后台产品分类下的数据，前后台分类通过showType区分
     *
     * @param redisDTO
     * @return java.util.List<TariffProductItemPriceTariffVO>
     * @author tanbiao
     * @modifier
     * @since 2020/3/26
     */
    @Cacheable(
            key = "'dubbo:tariff:channel:' + #redisDTO.channelId + ':city:' + #redisDTO.cityId + ':bizType:' + #redisDTO.bizType + ':servCategId:' + #redisDTO.servCategId"
                    + " + ':categId:' + #redisDTO.categId + ':showType:' + #redisDTO.showType + ':filterTariff:' + #redisDTO.filterTariff",
            cacheNames = "redis5m", unless = "#result == null || #result.size() <= 0")
    @Override
    public List<TariffProductItemPriceTariffVO> listRelatedTariffProductByRedisDTO(TariffProductRedisDTO redisDTO) {
        log.info("listRelatedTariffProductByRedisDTO 参数为：{}", JSON.toJSONString(redisDTO));
        Integer channelId = redisDTO.getAvaliableChannelId();
        if (Objects.isNull(channelId)) {
            Integer avaliableChannelId = channelServiceCategoryBService.getAvailableCategoryChannelId(redisDTO.getChannelId());
            channelId = avaliableChannelId;
        }
        Integer cityId = redisDTO.getCityId();
        Integer bizType = redisDTO.getBizType();
        Integer showType = redisDTO.getShowType();
        Integer servCategId = redisDTO.getServCategId();
        Integer categId = redisDTO.getCategId();
        Integer filterTariff = redisDTO.getFilterTariff();

        // 获取渠道配置的价格表，没有配置那么取产品的默认价格表
        Integer tariffId = getDefaultTarrIdForProducts(channelId, bizType);
        // 前台产品分类对应的后台产品分类集合
        List<ShowCategoryAssociationVO> list = new ArrayList<>();
        if (Objects.equals(showType, ProductDict.EC_PRODUCT_TYPE)) {
            list = showCategoryAssociationService.listByShowCategoryId(servCategId, null, categId);
        } else {
            list = showCategoryAssociationBService.listByCategoryId(servCategId, null, categId);
        }
        if (CollectionUtils.isEmpty(list)) {
            log.info("服务分类产品分类二级分类数据不存在，请检查参数,errorCode:{}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_CATEG_NO_RELATION);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_CATEG_NO_RELATION);
        }

        // redis过期重新检查数据，关键字检索的时候已经对试点进行了判断处理（设置了filteredByKeyWord）无需再次处理试点
        list = checkSupportWhenTimeOut(list, redisDTO);

        // 服务分类，后台二级分类确定前台分类的名称
        Map<String, ShowCategoryAssociationVO> nameRelationMap = new HashMap<>();
        Map<Integer, ServTariffProductRelationVO> tariffProductRelationMap = new HashMap<>();
        list.stream().forEach(e -> nameRelationMap.put(e.getServCategId() + "_" + e.getCategId(), e));
        // 封装查询条件
        TariffProductItemPriceTariffQueryVO query = new TariffProductItemPriceTariffQueryVO();
        // 添加显示平台过滤条件
        // Channel channel = channelService.findByKey(channelId);
        query.setChannelId(channelId);
        query.setCityId(cityId);
        query.setTariffId(tariffId);
        query.setBizType(bizType);
        query.setProductCategIds(list);
        query.setTariffType(ProductDict.TRIFF_TYPE_TARIFF);
        // query.setPlat(channel.getPlat());
        // 查询价格表和产品的对应关系数据，存在一个产品同时对应多个开启的价格表问题，此处需要单独处理
        log.info("listRelatedTariffProductByRedisDTO.listTariffProductRelationByQuery 参数为：{}", JSON.toJSONString(query));
        List<TariffProductRelationVO> tariffProductRelationVOList = tariffProductFaultItemService.listTariffProductRelationByQuery(query);
        if (CollectionUtils.isEmpty(tariffProductRelationVOList)) {
            log.error("产品后台二级分类对应的后台产品不存在可用的价格表,errorCode:{}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_NO_TARIFF_TABLE_RELATION);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_NO_TARIFF_TABLE_RELATION);
        }
        query.setTariffProductRelationVOList(tariffProductRelationVOList);
        // 加载产品价格表的所有数据，价格表类型为计价器
        log.info("listRelatedTariffProductByRedisDTO.listTariffProductItemPriceTariffByQuery 参数为：{}", JSON.toJSONString(query));
        List<TariffProductItemPriceTariffVO> productFaultItemPriceList = tariffProductFaultItemService.listTariffProductItemPriceTariffByQuery(query);
        if (CollectionUtils.isEmpty(productFaultItemPriceList)) {
            log.error("产品价格表的所有数据为空价格表类型为计价器,query={},code={}", JSON.toJSONString(query),
                    PlatErrorCodeDict.ERROR_CODE_PRODUCT_TABLE_RELATION_QUERY_NO_DATA);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TABLE_RELATION_QUERY_NO_DATA);
        }
        // 对productFaultItemPriceList进行组装，形成完整的数据
        addAttrToItem(tariffProductRelationVOList, productFaultItemPriceList);
        productFaultItemPriceList = filterData(productFaultItemPriceList, tariffProductRelationMap, filterTariff, bizType);
        // 添加额外的信息，服务分类名称等
        addExtMessageToVo(productFaultItemPriceList, nameRelationMap, tariffProductRelationMap);
        return productFaultItemPriceList;
    }

    // 后台产品id查询故障项
    @Override
    public List<TariffProductItemPriceDRO> listByTariffBackProductItemCategDIO(TariffBackProductItemCategDIO productFaultItemDIO) {
        if (Objects.isNull(productFaultItemDIO) || !NumberUtil.isPositiveInteger(productFaultItemDIO.getProductId()) || !NumberUtil.isPositiveInteger(productFaultItemDIO.getTariffProductId())
                || !NumberUtil.isPositiveInteger(productFaultItemDIO.getChannelId()) || !NumberUtil.isPositiveInteger(productFaultItemDIO.getCityId())
                || !NumberUtil.isPositiveInteger(productFaultItemDIO.getFaultCategId()) || !NumberUtil.isPositiveInteger(productFaultItemDIO.getFilterTariff())) {
            log.error("listByTariffBackProductItemCategDIO error.productFaultItemDIO：{},errorCode:{}", productFaultItemDIO, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }

        Integer channelId = productFaultItemDIO.getChannelId();
        Integer cityId = productFaultItemDIO.getCityId();
        Integer bizType = productFaultItemDIO.getBizType();
        Integer productId = productFaultItemDIO.getProductId();
        Integer faultCategId = productFaultItemDIO.getFaultCategId();
        Integer brandId = productFaultItemDIO.getBrandId();
        ServProduct servProduct = servProductService.findByKey(productId);
        if (Objects.isNull(servProduct)) {
            log.error("listByTariffBackProductFaultItemCategDIO 产品对应的产品数据不存在，productId={},code={}", productId, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_RESULT_NOT_EXIST);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_RESULT_NOT_EXIST);
        }
        TariffProductRedisDTO redisDTO = new TariffProductRedisDTO();
        BeanCopyUtils.copyProperties(productFaultItemDIO, redisDTO);
        redisDTO.setServCategId(servProduct.getServCategId());
        redisDTO.setCategId(servProduct.getCategId());
        redisDTO.setShowType(ProductDict.ERP_PRODUCT_TYPE);

        List<TariffProductItemPriceTariffVO> productList = tariffProductBService.listRelatedTariffProductByRedisDTO(redisDTO);
        log.debug("productList:{}", productList);
        if (CollectionUtils.isEmpty(productList)) {
            log.error("listByTariffBackProductFaultItemCategDIO 价格表数据不存在，productId={},code={}", productId, PlatErrorCodeDict.ERROR_CODE_PRODUCT_FILTER_BY_SERVCATEG_CATEG_FROM_REDIS_NO_DATA);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_FILTER_BY_SERVCATEG_CATEG_FROM_REDIS_NO_DATA);
        }
        List<TariffProductItemPriceTariffVO> faultProductList =
                productList.stream().filter(e -> Objects.equals(e.getProductId(), productId) && Objects.equals(e.getFaultCategId(), faultCategId)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(faultProductList)) {
            log.error("listByTariffBackProductFaultItemCategDIO 价格表对应的项目类型不存在，productId={},faultCategId={},code={}", productId, faultCategId,
                    PlatErrorCodeDict.ERROR_CODE_PRODUCT_FAULTCATEGORY_TYPE_NO_DATA);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_FAULTCATEGORY_TYPE_NO_DATA);
        }
        /********************************* 计算价格 ************************************************/
        for (TariffProductItemPriceTariffVO vo : faultProductList) {
            // 计算价格,区分城市定价还是系数定价，城市定价只考虑品牌系数
            productFaultItemPriceBService.calPriceDetail(vo, new ItemPriceCalDTO(channelId, cityId, brandId, bizType, null));
        }
        List<TariffProductItemPriceDRO> list = transVoListToDroList(faultProductList);
        return list;
    }

    @Override
    public List<ProductServiceItemExcutePriceResultVo> listDefaultItemPriceByRelationDTOList(List<ProductTariffRelationDTO> list, ItemPriceCalDTO calDTO, Integer showType) {
        //价格表类型分类系数定价和城市定价，城市定价具有优先级，因此需要以定价类型为维度分开处理，最后归并
        if (CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }
        Map<String, ProductTariffRelationDTO> map = list.stream().collect(Collectors.toMap(e -> e.getProductId() + "_" + e.getTariffId(), e -> e, (k, v) -> k));

        List<ProductServiceItemExcutePriceResultVo> cityResultList = new ArrayList<>();
        // 城市定价（按照配置的城市维度优先取原始价格）
        List<ProductTariffRelationDTO> ratioPriceProductList = list.stream().filter(e -> Objects.equals(e.getPriceType(), ProductDict.TRIFF_PRICE_TYPE_CITY)).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(ratioPriceProductList)) {
            cityResultList = tariffProductFaultItemService.listDefaultItemByRelationAndCityId(ratioPriceProductList, calDTO.getCityId());
        }
        // 系数定价，排除城市维度已经存在产品，剩下的都走系数定价
        if (!CollectionUtils.isEmpty(cityResultList)) {
            List<Integer> cityProductIdList = cityResultList.stream().map(e -> e.getProductId()).collect(Collectors.toList());
            list = list.stream().filter(e -> !cityProductIdList.contains(e.getProductId())).collect(Collectors.toList());
        }
        List<ProductServiceItemExcutePriceResultVo> ratioResultList = tariffProductFaultItemService.listDefaultItemByRelation(list);

        List<ProductServiceItemExcutePriceResultVo> allResult = new ArrayList<>();
        if (!CollectionUtils.isEmpty(cityResultList)) {
            allResult.addAll(cityResultList);
        }
        if (!CollectionUtils.isEmpty(ratioResultList)) {
            allResult.addAll(ratioResultList);
        }

        /********************************* 计算价格 ************************************************/
        for (ProductServiceItemExcutePriceResultVo vo : allResult) {
            addExtMsg(vo, map.get(vo.getProductId() + "_" + vo.getTariffId()), showType);
            // 计算价格,区分城市定价还是系数定价，城市定价只考虑品牌系数
            productFaultItemPriceBService.calPriceDetail(vo, calDTO);
        }

        return allResult;
    }

    //serv_category_group

    @Override
    @Cacheable(cacheNames = "redis5m", key = "'dubbo:tariff:ServAndCateg:channel:'+#p0+':cityId:'+#p1", unless = "#result.size() <= 0")
    public List<ServCategoryChildrenDRO> listServAndCategByChannelIdAndCity(Integer channelId, Integer cityId) {

        // 查询有效的服务分类
        ServCategory servQuery = new ServCategory();
        Map<Integer, List<ServCategory>> servMap = Optional.ofNullable(servCategoryService.listByQuery(servQuery))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(ServCategory::getCategId));

        // 查询有效的前台产品分类
        BaseCategoryQuery categoryQuery = new BaseCategoryQuery();
        categoryQuery.setStatus(GlobalConsts.YES);
        categoryQuery.setShowType(ProductConsts.EC_PRODUCT_TYPE);
        Map<Integer, List<BaseCategory>> categoryMap = Optional.ofNullable(
                baseCategoryService.listByQuery(categoryQuery))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(BaseCategory::getCategId));

        // 查询支持计价器的产品品类
        List<ServCategAndCategTwoQuery> collect1 = Optional.ofNullable(this.listServProductForTariff(channelId, cityId))
                .orElse(Collections.emptyList())
                .stream()
                .map(e -> new ServCategAndCategTwoQuery(e.getServCategId(), e.getCategOneId(), e.getCategId()))
                .distinct()
                .collect(Collectors.toList());


        // 按服务分类分组
        Map<Integer, List<ServCategAndCategTwoQuery>> serviceCategoryMap = collect1.stream().collect(groupingBy(ServCategAndCategTwoQuery::getServCategId));
        List<ServCategoryChildrenDRO> ret = serviceCategoryMap.values().stream().map(serviceCategory -> {
            // 按一级分类分组
            Map<Integer, List<ServCategAndCategTwoQuery>> categoryOneMap = serviceCategory.stream().collect(groupingBy(ServCategAndCategTwoQuery::getCategOneId));
            List<ServCategoryChildrenDRO> categoryOneList = categoryOneMap.values().stream().map(categoryOne -> {
                // 二级分类
                List<ServCategoryChildrenDRO> categList = categoryOne.stream()
                        .map(p -> {
                            BaseCategory baseCategory = categoryMap.get(p.getCategTwoId()).get(0);
                            return new ServCategoryChildrenDRO(baseCategory.getCategId(), baseCategory.getTariffName(), baseCategory.getSort(), baseCategory.getIcon(), baseCategory.getSimpleSpell(), null);
                        })
                        .collect(Collectors.toList());
                // 一级分类KvDTO
                BaseCategory baseCategory = categoryMap.get(categoryOne.get(0).getCategOneId()).get(0);
                return new ServCategoryChildrenDRO(baseCategory.getCategId(), baseCategory.getTariffName(), baseCategory.getSort(), baseCategory.getIcon(), baseCategory.getSimpleSpell(), categList);
            }).collect(Collectors.toList());
            // 服务分类
            ServCategory servCategory = servMap.get(serviceCategory.get(0).getServCategId()).get(0);
            return new ServCategoryChildrenDRO(servCategory.getCategId(), servCategory.getTariffName(), servCategory.getSort(), servCategory.getShowHomePageIcon(), servCategory.getShowSimpleSpell(), categoryOneList);

        }).collect(Collectors.toList());

        return ret;
    }

    @Override
    @Cacheable(cacheNames = "redis5m", key = "'dubbo:tariff:TwoCateg:channel:'+#p0+':cityId:'+#p1", unless = "#result == null")
    public TariffCategoryPageDRO listTwoCategByChannelIdAndCity(Integer channelId, Integer cityId) {

        // 查询有效的服务分类
        ServCategory servQuery = new ServCategory();
        Map<Integer, List<ServCategory>> servMap = Optional.ofNullable(servCategoryService.listByQuery(servQuery))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(ServCategory::getCategId));

        // 查询有效的前台产品分类
        BaseCategoryQuery categoryQuery = new BaseCategoryQuery();
        categoryQuery.setStatus(GlobalConsts.YES);
        categoryQuery.setShowType(ProductConsts.EC_PRODUCT_TYPE);
        Map<Integer, List<BaseCategory>> categoryMap = Optional.ofNullable(
                baseCategoryService.listByQuery(categoryQuery))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(BaseCategory::getCategId));

        // 查询支持计价器的产品品
        List<TariffCategoryDRO> collect1 = Optional.ofNullable(this.listServProductForTariff(channelId, cityId))
                .orElse(Collections.emptyList())
                .stream()
                .map(p -> {
                    ServCategory servCategory = servMap.get(p.getServCategId()).get(0);
                    BaseCategory baseCategory = categoryMap.get(p.getCategId()).get(0);
                    TariffCategoryDRO tariffCategory = new TariffCategoryDRO();
                    BeanCopyUtils.copyProperties(baseCategory, tariffCategory);
                    tariffCategory.setServCategId(servCategory.getCategId());
                    return tariffCategory;
                })
                .distinct()
                .collect(Collectors.toList());

        TariffCategoryPageDRO dro = new TariffCategoryPageDRO(collect1.size(), collect1);
        return dro;
    }

    private void addExtMsg(ProductServiceItemExcutePriceResultVo excutePriceResultVo, ProductTariffRelationDTO dto, Integer showType) {
        excutePriceResultVo.setServiceMinutes(Objects.isNull(excutePriceResultVo.getServiceMinutes()) ? GlobalConsts.NONE : excutePriceResultVo.getServiceMinutes());
        excutePriceResultVo.setDesc(Objects.nonNull(dto) ? dto.getDesc() : "");
        excutePriceResultVo.setSpecialDesc(Objects.nonNull(dto) ? dto.getSpecialDesc() : "");
        excutePriceResultVo.setBizType(Objects.nonNull(dto) ? dto.getBizType() : null);
        excutePriceResultVo.setPriceType(Objects.nonNull(dto) ? dto.getPriceType() : null);

        // 前台产品的属性值需要进行变换，具体的变化规则为：
        // 1.项目名称：后台产品二级分类名称+产品属性
        // 2.项目分组：项目名称
        // 3.产品名称：前台产品名称
        if (Objects.equals(ProductDict.EC_PRODUCT_TYPE, showType)) {
            excutePriceResultVo.setGroupName(excutePriceResultVo.getItemName());
            excutePriceResultVo.setItemName(getSeqName(excutePriceResultVo.getProductId(), excutePriceResultVo.getSequence(), excutePriceResultVo.getCategId()));
        }
        BaseCategory categOne = baseCategoryService.findByKeyOfCache(excutePriceResultVo.getCategOneId());
        BaseCategory categTwo = baseCategoryService.findByKeyOfCache(excutePriceResultVo.getCategId());
        excutePriceResultVo.setBackProductCategOneName(Objects.nonNull(categOne) ? categOne.getName() : "");
        if (Objects.nonNull(categTwo)) {
            excutePriceResultVo.setBackProductCategTwoName(categTwo.getName());
            excutePriceResultVo.setBackProductCategTwoId(categTwo.getCategId());
            excutePriceResultVo.setBackProductCategTwoSort(categTwo.getSort());
        }
    }

    private List<TariffProductItemPriceTariffVO> filterData(List<TariffProductItemPriceTariffVO> productFaultItemPriceList, Map<Integer, ServTariffProductRelationVO> tariffProductRelationMap,
                                                            Integer filterTariff, Integer bizType) {
        // 后台产品关联的前台产品必须为上架
        // 后台产品id
        List<Integer> productIds = productFaultItemPriceList.stream().map(e -> e.getProductId()).distinct().collect(Collectors.toList());
        // 根据后台产品id集合查询对应的前台产品
        List<ServProductRelationVO> showProductList = servProductRelationService.listShowProductByProductIds(productIds);
        if (CollectionUtils.isEmpty(showProductList)) {
            log.error("产品价格表的所有数据后台产品查询前台产数据为空,productIds={},code=", JSON.toJSONString(productIds),
                    PlatErrorCodeDict.ERROR_CODE_PRODUCT_SHOW_PRODUCT_NO_DATA);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_SHOW_PRODUCT_NO_DATA);
        }

        // 过滤业务类型，产品的业务类型包含价格表的业务类型
        if (Objects.equals(filterTariff, GlobalConsts.YES)) {
            showProductList = showProductList.stream().filter(e -> {
                if (StringUtil.isNotBlank(e.getBizType()) && StringUtil.isNotBlank(e.getShowBizType())) {
                    return e.getBizType().contains(bizType.toString()) && e.getShowBizType().contains(bizType.toString());
                }
                return false;
            }).collect(Collectors.toList());
        }

        // 前台产品为启用，后台产品状态和计价器状态同时为启用
        List<Integer> enableProductIdList = showProductList.stream()
                .filter(e -> Objects.equals(e.getStatus(), GlobalConsts.YES) && Objects.equals(e.getTariffStatus(), GlobalConsts.YES) && Objects.equals(e.getShowStatus(), GlobalConsts.YES))
                .map(e -> e.getProductId()).collect(Collectors.toList());

        // 再次筛选符合条件的后台产品数据
        productFaultItemPriceList = productFaultItemPriceList.stream().filter(e -> enableProductIdList.contains(e.getProductId())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(productFaultItemPriceList)) {
            log.error("产品价格表的所有数据前台产品满足条件的数据空，code={}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_SHOW_PRODUCT_ALL_UNSHIFT);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_SHOW_PRODUCT_ALL_UNSHIFT);
        }

        // 根据后台产品id集合查询对应的计价器产品
        // 经过筛选之后符合前台产品启用的后台产品id
        productIds = productFaultItemPriceList.stream().map(e -> e.getProductId()).distinct().collect(Collectors.toList());
        List<ServTariffProductRelationVO> tariffProductList = tariffProductRelationService.listTariffProductByProductIds(productIds);
        if (CollectionUtils.isEmpty(tariffProductList)) {
            log.error("产品价格表的所有数据进过前台筛选之后，后产关联的计价器数据为空,productIds={},code={}", JSON.toJSONString(productIds),
                    PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_NO_DATA);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_NO_DATA);
        }
        tariffProductList.stream().forEach(e -> tariffProductRelationMap.put(e.getProductId(), e));

        // 过滤业务类型，产品的业务类型包含价格表的业务类型
        if (Objects.equals(filterTariff, GlobalConsts.YES)) {
            tariffProductList = tariffProductList.stream().filter(e -> {
                if (StringUtil.isNotBlank(e.getBizType()) && StringUtil.isNotBlank(e.getBackProductBizType())) {
                    return e.getBizType().contains(bizType.toString()) && e.getBackProductBizType().contains(bizType.toString());
                }
                return false;
            }).collect(Collectors.toList());
        }

        // 前台产品为启用，后台产品状态和计价器状态同时为启用
        List<Integer> enableProductIdListTariff = tariffProductList.stream()
                .filter(e -> Objects.equals(e.getStatus(), GlobalConsts.YES) && Objects.equals(e.getTariffStatus(), GlobalConsts.YES) && Objects.equals(e.getBackProductTariffStatus(), GlobalConsts.YES))
                .map(e -> e.getProductId()).collect(Collectors.toList());

        // 再次筛选符合条件的后台产品数据
        productFaultItemPriceList = productFaultItemPriceList.stream().filter(e -> enableProductIdListTariff.contains(e.getProductId())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(productFaultItemPriceList)) {
            log.error("产品价格表的所有数据进过前台筛选之后，满足条件的计价器产品为空,code={}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_ALL_UNSHIFT);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_ALL_UNSHIFT);
        }
        return productFaultItemPriceList;
    }

    private List<ShowCategoryAssociationVO> checkSupportWhenTimeOut(List<ShowCategoryAssociationVO> list, TariffProductRedisDTO redisDTO) {
        if (Objects.equals(redisDTO.getFilterTariff(), GlobalConsts.YES) && !Objects.equals(redisDTO.getFilteredByKeyWord(), GlobalConsts.YES)) {
            List<Integer> servCategIds = new ArrayList<>();
            List<Integer> categIds = new ArrayList<>();
            list.forEach(e -> {
                servCategIds.add(e.getShowServCategId());
                categIds.add(e.getShowCategId());
            });

            Integer servCategId = redisDTO.getServCategId();
            Integer categId = redisDTO.getCategId();
            if (Objects.equals(redisDTO.getShowType(), ProductDict.ERP_PRODUCT_TYPE)) {
                List<ShowCategoryAssociationVO> showCategoryAssociationVOS = showCategoryAssociationBService.listByCategoryId(redisDTO.getServCategId(), null, redisDTO.getCategId());
                if (CollectionUtils.isEmpty(showCategoryAssociationVOS)) {
                    log.error("后台品类没有对应的前台品类");
                    return list;
                }
                servCategId = showCategoryAssociationVOS.get(0).getShowServCategId();
                categId = showCategoryAssociationVOS.get(0).getShowCategId();
            }

            // 查询支持计价器的分类列表
            SupportPilotVO supportPilotVO = channelPriceBService.listPilotCategs(redisDTO.getChannelId(), redisDTO.getCityId(), OnePriceConsts.TARIFF, servCategId, categId);

            if (Objects.isNull(supportPilotVO) || CollectionUtils.isEmpty(supportPilotVO.getServCategIdList())) {
                log.info("二级分类下的数据不支持计价器试点，channelId={},cityId={},showCategId={},code={}", redisDTO.getChannelId(), redisDTO.getCityId(), redisDTO.getServCategId(),
                        PlatErrorCodeDict.ERROR_CODE_PRODUCT_SHOW_CATEG_TIME_NOT_SUPPORT_TARIFF);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_SHOW_CATEG_TIME_NOT_SUPPORT_TARIFF);
            }

            Integer avaliableChannelId = redisDTO.getChannelId();
            // 筛选出支持计价器试点的数据,只考虑服务分类，二级分类是相同的
            List<Integer> supportServCategIds = supportPilotVO.getServCategIdList().stream().map(e -> e.getServCategId()).distinct().collect(Collectors.toList());
            //检查当前渠道开通的试点是否存在开通的分类
            List<ChannelServiceCategory> listCategory = channelServiceCategoryService.listByChannelIdAndCategIdAndShowType(redisDTO.getChannelId(), categIds, ProductDict.EC_PRODUCT_TYPE);
            if (CollectionUtils.isEmpty(listCategory)) {
                avaliableChannelId = channelServiceCategoryBService.getAvailableCategoryChannelId(redisDTO.getChannelId());
                log.info("二级渠道没有用可用的分类，取一级渠道的id,channelId:{},avaliableChannelId:{}", redisDTO.getChannelId(), avaliableChannelId);
                listCategory = channelServiceCategoryService.listByChannelIdAndCategIdAndShowType(avaliableChannelId, categIds, ProductDict.EC_PRODUCT_TYPE);
            }
            if (CollectionUtils.isEmpty(listCategory)) {
                log.info("二级渠道继承的一级渠道无可用的分类,errorCode:{}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PARENT_CHANNEL_NO_CATEGORY);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PARENT_CHANNEL_NO_CATEGORY);
            }

            Set<Integer> channelSupportServCategIds = listCategory.stream().map(e -> e.getServCategId()).collect(Collectors.toSet());
            //二者交集
            channelSupportServCategIds.retainAll(supportServCategIds);
            supportServCategIds.clear();
            supportServCategIds.addAll(channelSupportServCategIds);
            if (CollectionUtils.isEmpty(supportServCategIds)) {
                log.info("二级渠道继承的一级渠道和二级渠道的试点无交集,errorCode:{}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PARENT_CHANNEL_CATEGORY_TIME_OUT_NO_INTERSECTION);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PARENT_CHANNEL_CATEGORY_TIME_OUT_NO_INTERSECTION);
            }
            redisDTO.setAvaliableChannelId(avaliableChannelId);

            list = list.stream().filter(e -> supportServCategIds.contains(e.getShowServCategId())).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(list)) {
                log.info("服务分类产品分类二级分类数据不存在，请检查参数,errorCode:{}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_CATEG_TIME_OUT_NO_RELATION);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_CATEG_TIME_OUT_NO_RELATION);
            }
            return list;
        }
        return list;
    }

    /**
     * 描述: 过滤业务类型
     **/
    private List<ProductServiceItemExcutePriceResultVo> filterByBizType(Integer productId, Integer bizType, List<ProductServiceItemExcutePriceResultVo> cityResultVoList) {
        // 过滤业务类型：如果是前台产品那么查出的数据对应的后台产品业务类型必须部分相同，价格表业务类型必须被后台产品的业务类型包含
        ServProduct product = servProductService.findByKey(productId);
        Set<Integer> bizTypeList = new HashSet<>(StringUtil.convertStrsToList(product.getBizType().replaceAll("\\$", ",")));
        // 前台需要过滤后台业务类型和价格表业务类型
        if (Objects.equals(product.getShowType(), ProductDict.EC_PRODUCT_TYPE)) {
            return cityResultVoList.stream().filter(e -> {
                Set<Integer> productTypeList = new HashSet<>(StringUtil.convertStrsToList(e.getProductBizType().replaceAll("\\$", ",")));
                if (productTypeList.contains(bizType)) {
                    productTypeList.retainAll(bizTypeList);
                    return !CollectionUtils.isEmpty(productTypeList);
                }
                return false;
            }).collect(Collectors.toList());
        }

        // 后台业务类型和价格表业务类型保持一致
        if (Objects.equals(product.getShowType(), ProductDict.ERP_PRODUCT_TYPE)) {
            return cityResultVoList.stream().filter(e -> {
                List<Integer> productTypeList = StringUtil.convertStrsToList(e.getProductBizType().replaceAll("\\$", ","));
                return productTypeList.contains(bizType);
            }).collect(Collectors.toList());
        }
        // 其他类型不考虑
        return cityResultVoList;
    }

    /**
     * 描述: 设置服务分类名称等
     **/
    private void addExtMessageToVo(List<TariffProductItemPriceTariffVO> list, Map<String, ShowCategoryAssociationVO> nameRelationMap,
                                   Map<Integer, ServTariffProductRelationVO> tariffProductRelationMap) {
        if (!CollectionUtils.isEmpty(list)) {
            for (TariffProductItemPriceTariffVO vo : list) {
                String key = vo.getServCategId() + "_" + vo.getCategId();
                ShowCategoryAssociationVO associationVO = nameRelationMap.get(key);
                ServTariffProductRelationVO relationVO = tariffProductRelationMap.get(vo.getProductId());
                if (!Objects.isNull(associationVO)) {
                    vo.setShowCategId(associationVO.getShowCategId());
                    vo.setShowCategOneId(associationVO.getShowCategOneId());
                    vo.setShowServCategName(associationVO.getShowServCategName());
                    vo.setShowCategOneName(associationVO.getShowCategOneName());
                    vo.setShowCategName(associationVO.getShowCategName());
                    vo.setServCategName(associationVO.getServCategName());
                    vo.setCategOneName(associationVO.getCategOneName());
                    vo.setCategName(associationVO.getCategName());
                }
                if (!Objects.isNull(relationVO)) {
                    vo.setTariffProductId(relationVO.getTariffProductId());
                    vo.setTariffProductName(relationVO.getName());
                }
                // 针对项目未设置服务时长取前台产品二级分类的服务时长
                if (NumberUtil.isNullOrZero(vo.getServiceMinutes())) {
                    vo.setServiceMinutes(GlobalConsts.NONE);
                }

            }
        }
    }

    /**
     * 功能描述 ：对价格表数据进行拼装
     *
     * @param tariffProductRelationVOList
     * @param productFaultItemPriceList
     * @return void
     * @author tanbiao
     * @modifier
     * @since 2020/4/23
     */
    private void addAttrToItem(List<TariffProductRelationVO> tariffProductRelationVOList, List<TariffProductItemPriceTariffVO> productFaultItemPriceList) {
        Map<Integer, TariffProductRelationVO> relationVOMap = new HashMap<>();
        tariffProductRelationVOList.forEach(e -> relationVOMap.put(e.getProductId(), e));
        BeanCopier temCopier = BeanCopier.create(TariffProductRelationVO.class, TariffProductItemPriceTariffVO.class, false);
        for (TariffProductItemPriceTariffVO vo : productFaultItemPriceList) {
            TariffProductRelationVO relationVO = relationVOMap.get(vo.getProductId());
            temCopier.copy(relationVO, vo, null);
        }
    }

    /**
     * 描述: 将数据缩小100保留2位小数
     *
     * @param dividend 被除数
     * @return double
     * @author wangjie
     * @since 10:36 2019/4/20
     **/
    private String narrow(Object dividend) {
        if (Objects.isNull(dividend)) {
            return "--";
        }
        double div = MathUtil.div(Integer.parseInt(dividend.toString()), MasterDict.COEFFICIENT_MAGNIFICATION, 2);
        BigDecimal b = new BigDecimal(div);
        DecimalFormat df = new DecimalFormat(",###,##0.00");
        return df.format(b);
    }

    /**
     * 功能描述 ：对公共信息进行装换，要根据产品类型对不同字段复制主要为： 1.后台产品，显示信息不变 2.前台产品，项目分组名称为项目名称 ，项目名称为后台产品名称
     *
     * @param vo
     * @param excutePriceResultVo
     * @param showType
     * @return void
     * @author tanbiao
     * @modifier
     * @since 2020/3/18
     */
    private void transLateVo(ChannelServiceTariffVO vo, ProductServiceItemExcutePriceResultVo excutePriceResultVo, Integer showType) {
        excutePriceResultVo.setTariffName(vo.getTariffName());
        excutePriceResultVo.setServCategName(vo.getServCategName());
        // 前台产品的属性值需要进行变换，具体的变化规则为：
        // 1.项目名称：后台产品二级分类名称+产品属性
        // 2.项目分组：项目名称
        // 3.产品名称：前台产品名称
        if (Objects.equals(ProductDict.EC_PRODUCT_TYPE, showType)) {
            excutePriceResultVo.setGroupName(excutePriceResultVo.getItemName());
            excutePriceResultVo.setItemName(getSeqName(excutePriceResultVo.getProductId(), excutePriceResultVo.getSequence(), excutePriceResultVo.getCategId()));
            excutePriceResultVo.setProductName(vo.getProductName());
            excutePriceResultVo.setServCategName(vo.getShowServCategName());
        }
        BaseCategory categOne = baseCategoryService.findByKeyOfCache(excutePriceResultVo.getCategOneId());
        BaseCategory categTwo = baseCategoryService.findByKeyOfCache(excutePriceResultVo.getCategId());
        excutePriceResultVo.setBackProductCategOneName(Objects.nonNull(categOne) ? categOne.getName() : "");
        if (Objects.nonNull(categTwo)) {
            excutePriceResultVo.setBackProductCategTwoName(categTwo.getName());
            excutePriceResultVo.setBackProductCategTwoId(categTwo.getCategId());
            excutePriceResultVo.setBackProductCategTwoSort(categTwo.getSort());
        }
        excutePriceResultVo.setCategOneName(vo.getCategOneName());
        excutePriceResultVo.setCategName(vo.getCategName());
        excutePriceResultVo.setInternalSettlementPriceStr(narrow(excutePriceResultVo.getInternalSettlementPrice()));
        excutePriceResultVo.setExternalSettlementPriceStr(narrow(excutePriceResultVo.getExternalSettlementPrice()));
        excutePriceResultVo.setTrafficFeeStr(narrow(excutePriceResultVo.getTrafficFee()));
        excutePriceResultVo.setHourFeeStr(narrow(excutePriceResultVo.getHourFee()));
        excutePriceResultVo.setServicePriceStr(narrow(excutePriceResultVo.getServicePrice()));
        excutePriceResultVo.setPartPriceStr(narrow(excutePriceResultVo.getPartPrice()));
        excutePriceResultVo.setArtPriceStr(narrow(excutePriceResultVo.getArtPrice()));
        excutePriceResultVo.setGuaranteePriceStr(narrow(excutePriceResultVo.getGuaranteePrice()));
        excutePriceResultVo.setProductStatus(vo.getProductStatus());
        excutePriceResultVo.setTariffType(vo.getTariffType());
        excutePriceResultVo.setDesc(vo.getDesc());
        excutePriceResultVo.setSpecialDesc(vo.getSpecialDesc());
        excutePriceResultVo.setBizType(vo.getBizType());
    }

    private String getSeqName(Integer productId, String sequence, Integer categId) {
        try {
            return productEnuCache.get(productId, callerItem(sequence, categId));
        } catch (ExecutionException e) {
            log.error("getSeqName cache error.", e);
        }
        return null;
    }

    private Callable<String> callerItem(String sequence, Integer categId) {
        return () -> {
            List<Integer> attrIds = new ArrayList<>();
            if (StringUtil.isNotBlank(sequence) && sequence.indexOf("&") != -1) {
                String[] seqArray = sequence.split(",");
                for (String seq : seqArray) {
                    if (StringUtil.isNotBlank(seq) && seq.indexOf("&") != -1) {
                        String[] enumIdArray = seq.split("&");
                        if (enumIdArray.length > 1 && !Objects.equals(enumIdArray[0], enumIdArray[1])) {
                            attrIds.add(Integer.valueOf(enumIdArray[1]));
                        }
                    }
                }
            }
            List<BaseCategoryAttributeEnum> enumList = new ArrayList<>();
            if (!CollectionUtils.isEmpty(attrIds)) {
                enumList = baseCategoryAttributeEnumService.listByKeys(attrIds);
            }
            StringBuilder stringBuilder = new StringBuilder();
            if (CollectionUtils.isEmpty(enumList)) {
            } else {
                enumList.forEach(e -> {
                    stringBuilder.append(e.getEnumValue()).append(",");
                });
                if (stringBuilder.length() > 0) {
                    stringBuilder.deleteCharAt(stringBuilder.length() - 1);
                }
            }
            String name = Optional.ofNullable(baseCategoryService.findByKey(categId).getName()).orElse("");
            return name + stringBuilder.toString();
        };
    }

    /**
     * 功能描述 :计算项目价格，并归并返回实体
     *
     * @param list
     * @param channelId
     * @param cityId
     * @param bizType
     * @param brandId
     * @return java.util.List<com.zmn.plat.common.dto.product.tariff.item.TariffProductFaultItemPriceUnknownDRO>
     * @author tanbiao
     * @modifier
     * @since 2020/3/28
     */
    private List<TariffProductItemPriceUnknownDRO> calcPriceAndTransVoToDro(List<TariffProductItemPriceTariffVO> list, Integer channelId, Integer cityId, Integer bizType, Integer brandId) {
        if (CollectionUtils.isEmpty(list)) {
            log.info("calcPriceAndTransVoToDro 集合为空，返回空，不做任何处理");
            return Collections.EMPTY_LIST;
        }
        /**************************** 计算价格 *****************************************************/
        Map<Integer, TariffProductItemPriceUnknownDRO> retListMap = new HashMap<>();
        String brandName = "";
        if (!Objects.isNull(brandId)) {
            BaseBrand brand = baseBrandService.findByKey(brandId);
            brandName = brand.getName();
        }

        BeanCopier temCopier = BeanCopier.create(TariffProductItemPriceTariffVO.class, TariffProductItemPriceDRO.class, false);
        for (TariffProductItemPriceTariffVO vo : list) {
            // 一口价系数定价需要计算价格
            if (Objects.equals(vo.getPriceType(), ProductDict.TRIFF_PRICE_TYPE_RATIO) && Objects.equals(vo.getPriceStandard(), GlobalConsts.YES)) {
                // 区分城市定价还是系数定价，城市定价只考虑品牌系数
                productFaultItemPriceBService.calPriceDetail(vo, new ItemPriceCalDTO(channelId, cityId, brandId, bizType, null));
            }
            // 由于没有确定后台产品，存在多个后台产品的情况，需要分别处理
            TariffProductItemPriceDRO innerDro = new TariffProductItemPriceDRO();
            temCopier.copy(vo, innerDro, null);
            TariffProductItemPriceUnknownDRO dro = retListMap.get(vo.getProductId());
            if (dro == null) {
                dro = new TariffProductItemPriceUnknownDRO();
                dro.setBrandName(brandName);
                dro.setProductId(vo.getProductId());
                dro.setProductName(vo.getProductName());
                dro.setProductTariffName(vo.getProductTariffName());
                dro.setFaultItemDROS(new ArrayList<>());
                dro.getFaultItemDROS().add(innerDro);
                retListMap.put(vo.getProductId(), dro);
            } else {
                dro.getFaultItemDROS().add(innerDro);
            }
        }
        List<TariffProductItemPriceUnknownDRO> retList = new ArrayList<>();
        retList.addAll(retListMap.values());
        return retList;
    }

    /**
     * 渠道配置的计价器类型的价格表，有可能为空，为空需要根据产品查询默认价格表
     *
     * @param channelId
     * @param bizType
     * @return
     */
    private Integer getDefaultTarrIdForProducts(Integer channelId, Integer bizType) {
        // 查询渠道是否配置了故障价格表
        Integer tariffId = null;
        ChannelServiceTariffVO channelFaultPrice = channelTariffService.findFaultTariffByChannelId(channelId, bizType, ProductDict.TRIFF_TYPE_TARIFF);
        if (null != channelFaultPrice) {
            tariffId = channelFaultPrice.getTariffId();
        }
        log.info("getDefaultTarrIdForProducts return tariffId={},channelId={},bizType={}", tariffId, channelId, bizType);
        return tariffId;
    }

    /**
     * 功能描述 :内存分页，涉及到渠道试点的数据需要进行筛选，导致数据缺失的情况
     *
     * @param result
     * @param pageNum
     * @param pageSize
     * @return java.util.List<U>
     * @author tanbiao
     * @modifier
     * @since 2020/3/27
     */
    private static <U> List<U> listPage(List<U> result, Integer pageNum, Integer pageSize) {
        List<U> returnList = new ArrayList<>();
        Integer from = (pageNum - 1) * pageSize;
        Integer to = pageNum * pageSize;
        if (from > result.size()) {
            return Lists.newArrayList();
        }
        if (result.size() > to) {
            returnList = result.subList(from, to);
        } else {
            returnList = result.subList(from, result.size());
        }
        return returnList;
    }

    /**
     * 功能描述 :一个计价器产品对应的配置了价格表的所有后台产品数据
     *
     * @param dto 渠道id
     * @return java.util.List<com.zmn.plat.model.vo.product.tariff.TariffProductItemPriceTariffVO>
     * @author tanbiao
     * @modifier
     * @since 2020/3/27
     */
    private List<TariffProductItemPriceTariffVO> listProductByChannelIdAndCityIdAndBizTypeAndTariffProductId(BaseParamDTO dto) {
        ServProduct servProduct = servProductService.findByKey(dto.getTariffProductId());
        Integer tariffProductId = dto.getTariffProductId();
        if (Objects.isNull(servProduct)) {
            log.error("listProductByChannelIdAndCityIdAndBizTypeAndTariffProductId 产品对应的产品数据不存在，tariffProductId={}，code={}", tariffProductId,
                    PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_NOT_EXIST);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_NOT_EXIST);
        }
        TariffProductRedisDTO redisDTO = new TariffProductRedisDTO();
        BeanCopyUtils.copyProperties(dto, redisDTO);
        redisDTO.setServCategId(servProduct.getServCategId());
        redisDTO.setCategId(servProduct.getCategId());
        redisDTO.setShowType(ProductDict.EC_PRODUCT_TYPE);
        List<TariffProductItemPriceTariffVO> productVoList = tariffProductBService.listRelatedTariffProductByRedisDTO(redisDTO);

        // 计价器产品与前台产品却区别
        List<Integer> backProductIds = new ArrayList<>();
        if (Objects.equals(ProductDict.EC_PRODUCT_TYPE, servProduct.getShowType())) {
            // 筛选符合该前台产品的所有项目
            ServProductRelationQuery query = new ServProductRelationQuery();
            query.setShowProductId(servProduct.getProductId());
            List<ServProductRelation> relations = servProductRelationService.listByQuery(query);
            if (CollectionUtils.isEmpty(relations)) {
                log.error("前台关联关系不存在 tariffProductId={},code={}", tariffProductId, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_RELATION_NOT_EXIST);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_RELATION_NOT_EXIST);
            }
            backProductIds = relations.stream().map(e -> e.getProductId()).collect(Collectors.toList());
        } else {
            // 筛选符合该计价器产品的所有项目
            ServTariffProductRelationQuery query = new ServTariffProductRelationQuery();
            query.setTariffProductId(servProduct.getProductId());
            List<ServTariffProductRelation> relations = tariffProductRelationService.listByQuery(query);
            if (CollectionUtils.isEmpty(relations)) {
                log.error("计价器关联关系不存在 tariffProductId={},code={}", tariffProductId, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_RELATION_NOT_EXIST);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_RELATION_NOT_EXIST);
            }
            backProductIds = relations.stream().map(e -> e.getProductId()).collect(Collectors.toList());
        }
        List<Integer> finalBackProductIds = backProductIds;

        List<TariffProductItemPriceTariffVO> tariffProductOneList = productVoList.stream().filter(e -> finalBackProductIds.contains(e.getProductId())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(tariffProductOneList)) {
            log.error("价格表数据中计价器产品对应的后台产品满足条件的数据为空 tariffProductId={},code={}", tariffProductId, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PRICETABNE_NO_DATA);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PRICETABNE_NO_DATA);
        }
        return tariffProductOneList;
    }

    /**
     * 功能描述 :一个计价器产品对应的配置了价格表的选择了指定项目的数据
     *
     * @param dto 参数
     * @return java.util.List<com.zmn.plat.model.vo.product.tariff.TariffProductItemPriceTariffVO>
     * @author tanbiao
     * @modifier
     * @since 2020/3/27
     */
    private List<TariffProductItemPriceTariffVO> filterBySelectItemIds(ItemFilterDTO dto) {
        log.info("filterBySelectItemIds 参数为：{}", JSON.toJSONString(dto));
        Integer tariffProductId = dto.getTariffProductId();
        List<Integer> selectedItems = dto.getItemIds();
        List<TariffProductItemPriceTariffVO> filterList = new ArrayList<>();
        Integer brandId = dto.getBrandId();
        // 一个计价器产品对应的所有配置了价格表的后台产品数据
        BaseParamDTO baseParamDTO = new BaseParamDTO();
        BeanCopyUtils.copyProperties(dto, baseParamDTO);
        List<TariffProductItemPriceTariffVO> tariffProductOneList = listProductByChannelIdAndCityIdAndBizTypeAndTariffProductId(baseParamDTO);
        // 根据故障项目类型筛选符合条件的数据，分两步筛选
        // 1.如果是首次筛选，不确定后续的项目，直接筛选集合
        // 2.如果不是第一次筛选，需要根据已选择的项目过滤不符合条件的数据
        if (!CollectionUtils.isEmpty(selectedItems)) {
            // 已选择的项目实际上是挂载后台产品上的，因此需要根据产品id对数据进行分组，要求每个产品对应的所有项目必须全包含已选择的项目
            // 只要确定了一个itemId,价格表就确定了，根据价格表id,再次筛选符合条件的数据
            Integer itemId = selectedItems.get(0);
            TariffProductItemPriceTariffVO oneVo = tariffProductOneList.stream().filter(e -> Objects.equals(e.getItemId(), itemId)).findFirst().get();
            // 同一个价格表中的所有配置了价格的后台产品
            tariffProductOneList = tariffProductOneList.stream().filter(e -> Objects.equals(e.getTariffId(), oneVo.getTariffId())).collect(Collectors.toList());
            // 再在当前的数据中过滤满足条件的所有数据，最终是为了确定后台产品，因此需要根据产品维度过滤数据,要求该产品必须包含所有的已选的项目
            Map<Integer, List<TariffProductItemPriceTariffVO>> voListMap = tariffProductOneList.stream().collect(Collectors.groupingBy(e -> e.getProductId()));
            for (Iterator<Map.Entry<Integer, List<TariffProductItemPriceTariffVO>>> it = voListMap.entrySet().iterator(); it.hasNext(); ) {
                Map.Entry<Integer, List<TariffProductItemPriceTariffVO>> volist = it.next();
                List<Integer> items = volist.getValue().stream().map(e -> e.getItemId()).collect(Collectors.toList());
                if (items.containsAll(selectedItems)) {
                    filterList.addAll(volist.getValue());
                }
            }
        } else {
            filterList.addAll(tariffProductOneList);
        }
        // 如果品牌不为空，根据品牌所在的二级分类再次筛选数据
        if (!NumberUtil.isNullOrZero(brandId)) {
            ServProduct servProduct = servProductService.findByKey(tariffProductId);
            if (Objects.isNull(servProduct)) {
                log.error("filterBySelectItemIds 产品对应的产品数据不存在，productId={},code={},brand={}", tariffProductId, PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_RESULT_NOT_EXIST, brandId);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_RESULT_NOT_EXIST);
            }
            TariffProductRedisDTO redisDTO = new TariffProductRedisDTO();
            BeanCopyUtils.copyProperties(dto, redisDTO);
            redisDTO.setServCategId(servProduct.getServCategId());
            redisDTO.setCategId(servProduct.getCategId());
            redisDTO.setShowType(ProductDict.EC_PRODUCT_TYPE);
            List<BrandFactorRatioVo> brandFactorRatioVos = tariffProductBService.listConfigedBrandByRedisDTO(redisDTO);
            brandFactorRatioVos = brandFactorRatioVos.stream().filter(e -> Objects.equals(e.getBrandId(), brandId)).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(brandFactorRatioVos)) {
                log.error("根据品牌筛选数据，该品牌在品牌系数中未配置数据，code={},brandId={}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_BRAND_NO_DATA, brandId);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_BRAND_NO_DATA);
            }
            List<String> configedCategorys = brandFactorRatioVos.stream().map(e -> e.getServCategId() + "_" + e.getCategOneId()).collect(Collectors.toList());
            filterList = filterList.stream().filter(e -> configedCategorys.contains(e.getServCategId() + "_" + e.getCategOneId())).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(filterList)) {
                log.error("根据品牌对应的分类筛选数据，该品牌在品牌系数中未配置数据,cdoe={},brandId={}", PlatErrorCodeDict.ERROR_CODE_PRODUCT_BRAND_CATEGORY_NO_DATA, brandId);
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_BRAND_CATEGORY_NO_DATA);
            }
        }
        return filterList;
    }

    private List<TariffProductItemPriceDRO> transVoListToDroList(List<TariffProductItemPriceTariffVO> items) {
        List<TariffProductItemPriceDRO> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(items)) {
            BeanCopier copier = BeanCopier.create(TariffProductItemPriceTariffVO.class, TariffProductItemPriceDRO.class, false);
            list = items.stream().map(e -> {
                TariffProductItemPriceDRO dro = new TariffProductItemPriceDRO();
                copier.copy(e, dro, null);
                return dro;
            }).collect(Collectors.toList());
        }
        return list;
    }

    private static List<BrandFactorRatioVo> filterByTariffProductId(List<BaseBrandTariffQuery> productCategorys, List<BrandFactorRatioVo> brandList) {
        // 筛选合法的数据
        Map<Integer, List<BrandFactorRatioVo>> categMap = new HashMap<>();
        Map<Integer, List<BrandFactorRatioVo>> categOneMap = new HashMap<>();
        brandList.stream().forEach(e -> {
            if (NumberUtil.isNotNullOrZero(e.getCategId())) {
                if (CollectionUtils.isEmpty(categMap.get(e.getCategId()))) {
                    List<BrandFactorRatioVo> twoList = new ArrayList<>();
                    twoList.add(e);
                    categMap.put(e.getCategId(), twoList);
                } else {
                    categMap.get(e.getCategId()).add(e);
                }
            } else {
                if (CollectionUtils.isEmpty(categOneMap.get(e.getCategOneId()))) {
                    List<BrandFactorRatioVo> oneList = new ArrayList<>();
                    oneList.add(e);
                    categOneMap.put(e.getCategOneId(), oneList);
                } else {
                    categOneMap.get(e.getCategOneId()).add(e);
                }
            }
        });

        List<Integer> brandIds = new ArrayList<>();
        List<BrandFactorRatioVo> filteredList = new ArrayList<>();
        for (BaseBrandTariffQuery vo : productCategorys) {
            List<BrandFactorRatioVo> twoList = categMap.get(vo.getCategTwoId());
            if (!CollectionUtils.isEmpty(twoList)) {
                for (BrandFactorRatioVo two : twoList) {
                    boolean isEq =
                            Objects.equals(vo.getServCategId(), two.getServCategId()) && Objects.equals(vo.getCategOneId(), two.getCategOneId()) && Objects.equals(vo.getCategTwoId(), two.getCategId());
                    if (isEq && !brandIds.contains(two.getBrandId())) {
                        brandIds.add(two.getBrandId());
                        filteredList.add(two);
                    }
                }
            }

            if (categOneMap.containsKey(vo.getCategOneId())) {
                List<BrandFactorRatioVo> oneList = categOneMap.get(vo.getCategOneId());
                if (!CollectionUtils.isEmpty(oneList)) {
                    for (BrandFactorRatioVo one : oneList) {
                        boolean isEq = Objects.equals(vo.getServCategId(), one.getServCategId()) && Objects.equals(vo.getCategOneId(), one.getCategOneId());
                        if (isEq && !brandIds.contains(one.getBrandId())) {
                            brandIds.add(one.getBrandId());
                            filteredList.add(one);
                        }
                    }
                }
            }
        }
        return filteredList;
    }

    private void setQueryParams(ProductServiceItemExcutePriceQueryVo query) {
        //结果过来的，不确定是否配置了可用的分类
        if (Objects.isNull(query.getCurrentChannelId())) {
            query.setCurrentChannelId(query.getChannelId());
            // 当前渠道是否存在合法的开通分类，不存在则变换渠道id为父级的渠道id
            Integer avaliableChannelId = channelServiceCategoryBService.getAvailableCategoryChannelId(query.getChannelId());
            query.setChannelId(avaliableChannelId);
        }
        ChannelServiceTariffVO vo = channelTariffService.findFaultTariffByChannelId(query.getChannelId(), query.getBizType(), query.getTariffType());
        if (null != vo) {
            log.debug("listByExcuteQuery 存在价格表，价格表id={}", vo.getTariffId());
            query.setTariffId(vo.getTariffId());
        }
    }

    private void handlePriceStandardYes(ProductServiceItemExcutePriceQueryVo query, ProductServiceItemExcutePriceResultVo excutePriceResultVo, ChannelServiceTariffVO channelFaultTariffVO) {
        // 区分城市定价还是系数定价，城市定价只考虑品牌系数
        productFaultItemPriceBService.calPriceDetail(excutePriceResultVo, new ItemPriceCalDTO(query.getChannelId(), query.getCityId(), query.getBrandId(), query.getBizType(), query.getDifficultId()));
        excutePriceResultVo.setPriceStr(narrow(excutePriceResultVo.getPrice()));
        if (Objects.equals(channelFaultTariffVO.getPriceType(), ProductDict.TRIFF_PRICE_TYPE_RATIO)) {
            if (NumberUtil.isPositiveInteger(excutePriceResultVo.getServicePrice())) {
                excutePriceResultVo.setServicePriceStr(narrow(excutePriceResultVo.getServicePrice()));
            }
            if (NumberUtil.isPositiveInteger(excutePriceResultVo.getPartPrice())) {
                excutePriceResultVo.setPartPriceStr(narrow(excutePriceResultVo.getPartPrice()));
            }
            if (NumberUtil.isPositiveInteger(excutePriceResultVo.getArtPrice())) {
                excutePriceResultVo.setArtPriceStr(narrow(excutePriceResultVo.getArtPrice()));
            }
            if (NumberUtil.isPositiveInteger(excutePriceResultVo.getGuaranteePrice())) {
                excutePriceResultVo.setGuaranteePriceStr(narrow(excutePriceResultVo.getGuaranteePrice()));
            }
            if (NumberUtil.isPositiveInteger(excutePriceResultVo.getCheckFee())) {
                excutePriceResultVo.setCheckFeeStr(narrow(excutePriceResultVo.getCheckFee()));
            }
        }

        transLateVo(channelFaultTariffVO, excutePriceResultVo, query.getShowType());
    }

    private void handPriceStandardNo(ProductServiceItemExcutePriceQueryVo query, ProductServiceItemExcutePriceResultVo excutePriceResultVo, ChannelServiceTariffVO channelFaultTariffVO) {
        if (NumberUtil.isNotNullOrZero(excutePriceResultVo.getNegotiableMaxPrice()) && NumberUtil.isNotNullOrZero(excutePriceResultVo.getNegotiableMinPrice())) {
            excutePriceResultVo.setPriceStr(narrow(excutePriceResultVo.getNegotiableMinPrice()) + "至" + narrow(excutePriceResultVo.getNegotiableMaxPrice()));
        } else {
            excutePriceResultVo.setPriceStr(narrow(excutePriceResultVo.getNegotiableMinPrice()));
        }
        transLateVo(channelFaultTariffVO, excutePriceResultVo, query.getShowType());
    }

    /**
     * 描述: 根据渠道id和城市查询支持计价器的产品
     *
     * @param channelId 渠道id
     * @param cityId 城市id
     * @author guoqiao
     * @since 2021/8/11 9:24
     */
    private List<ServProduct> listServProductForTariff(Integer channelId, Integer cityId) {
        try {
            Integer avaliableChannelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
            log.info("原渠道：{}，可用渠道：{}", channelId, avaliableChannelId);
            channelId = avaliableChannelId;
        } catch (PlatException e) {
            return null;
        }
        // 查询有效的服务分类
        ServCategory servQuery = new ServCategory();
        Map<Integer, List<ServCategory>> servMap = Optional.ofNullable(servCategoryService.listByQuery(servQuery))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(ServCategory::getCategId));

        // 查询有效的前台产品分类
        BaseCategoryQuery categoryQuery = new BaseCategoryQuery();
        categoryQuery.setStatus(GlobalConsts.YES);
        categoryQuery.setShowType(ProductConsts.EC_PRODUCT_TYPE);
        Map<Integer, List<BaseCategory>> categoryMap = Optional.ofNullable(
                baseCategoryService.listByQuery(categoryQuery))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(BaseCategory::getCategId));

        // 根据渠道id和城市id查询计价器试点分类
        SupportPilotVO supportPilotVO = channelPriceBService.listPilotCategs(channelId, cityId, OnePriceConsts.TARIFF, null, null);
        if (Objects.isNull(supportPilotVO) || CollectionUtils.isEmpty(supportPilotVO.getServCategIdList())) {
            log.error("没有开通试点的产品");
            return null;
        }
        List<String> politCollect = supportPilotVO.getServCategIdList()
                .stream()
                .map(m -> m.getServCategId() + "-" + m.getCategOneId() + "-" + m.getCategTwoId())
                .collect(Collectors.toList());

        // 渠道开通前台的服务分类
        List<String> channelServCollect = Optional.ofNullable(channelServiceCategoryDAO.listShowCategoryByChannelId(channelId))
                .orElse(Collections.emptyList())
                .stream()
                .map(i -> i.getServCategId() + "-" + i.getCategOneId() + "-" + i.getCategId())
                .collect(Collectors.toList());

        // 服务与产品的关联关系
        List<String> servAssCategoryCollect = Optional.ofNullable(servAssCategoryDao.listByQuery(new ServAssCategoryQuery()))
                        .orElse(Collections.emptyList())
                        .stream()
                        .map(i -> i.getServCategId() + "-" + i.getCategOneId() + "-" + i.getCategId())
                        .collect(Collectors.toList());

        // 渠道禁用的后台产品
        ChannelProductQuery channelProductQuery = ChannelProductQuery.builder()
                .channelId(channelId)
                .showType(ProductConsts.ERP_PRODUCT_TYPE)
                .status(GlobalConsts.NO)
                .build();
        List<Integer> disableProductIdS = Optional.ofNullable(channelServProductBService.listChannelServProductByQuery(channelProductQuery))
                .orElse(Collections.emptyList())
                .stream()
                .map(m -> m.getProductId())
                .collect(Collectors.toList());

        // 与后台产品有关联关系的计价器产品
        List<Integer> tariffProductIds = Optional.ofNullable(tariffProductRelationService.listByQuery(new ServTariffProductRelationQuery()))
                .orElse(Collections.emptyList())
                .stream()
                .filter(m -> !disableProductIdS.contains(m.getProductId()))
                .map(m -> m.getTariffProductId())
                .collect(Collectors.toList());

        Integer channelIdFin = channelId;

        // 查询计价器产品对应的品类
        ServProductQuery query = new ServProductQuery();
        query.setShowType(ProductConsts.ET_PRODUCT_TYPE);
        query.setStatus(GlobalConsts.YES);
        List<ServProduct> servProductList = Optional.ofNullable(servProductService.listByQuery(query))
                .orElse(Collections.emptyList())
                .stream()
                // 过滤服务分类和产品分类
                .filter(e -> servMap.containsKey(e.getServCategId()) && categoryMap.containsKey(e.getCategOneId()) && categoryMap.containsKey(e.getCategId()))
                // 过滤计价器试点分类
                .filter(e -> politCollect.contains(e.getServCategId() + "-" + e.getCategOneId() + "-" + e.getCategId()))
                // 过滤渠道开通的分类
                .filter(e -> channelServCollect.contains(e.getServCategId() + "-" + e.getCategOneId() + "-" + e.getCategId()))
                // 过滤服务分类和产品分类的关联关系
                .filter(e -> servAssCategoryCollect.contains(e.getServCategId() + "-" + e.getCategOneId() + "-" + e.getCategId()))
                // 过滤被渠道禁用的后台产品对对应的计价器产品
                .filter(e -> tariffProductIds.contains(e.getProductId()))
                // 过滤是否有可用价格表
                .filter(e -> productBService.checkTariffByProductIdAndShowType(e, channelIdFin, ProductConsts.ET_PRODUCT_TYPE, ProductConsts.BIZ_TYPE_C))
                .collect(Collectors.toList());
        return servProductList;
    }

}
